PageRenderTime 47ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/DICK.B1/IronPython.Modules/_bytesio.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 560 lines | 424 code | 100 blank | 36 comment | 93 complexity | de3628632a03324bd2950d6942636c91 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.IO;
  20. using System.Runtime.InteropServices;
  21. using System.Text;
  22. using Microsoft.Scripting.Runtime;
  23. using IronPython.Runtime;
  24. using IronPython.Runtime.Operations;
  25. using IronPython.Runtime.Types;
  26. using IronPython.Runtime.Exceptions;
  27. #if CLR2
  28. using Microsoft.Scripting.Math;
  29. #else
  30. using System.Numerics;
  31. #endif
  32. [assembly: PythonModule("_bytesio", typeof(IronPython.Modules.PythonBytesIOModule))]
  33. namespace IronPython.Modules {
  34. public static class PythonBytesIOModule {
  35. public const string __doc__ = null;
  36. /// <summary>
  37. /// BytesIO([initializer]) -> object
  38. ///
  39. /// Create a buffered I/O implementation using an in-memory bytes
  40. /// buffer, ready for reading and writing.
  41. /// </summary>
  42. [PythonType("_BytesIO")]
  43. [DontMapIDisposableToContextManager]
  44. public class _BytesIO : IEnumerator, IDisposable {
  45. #region Fields and constructors
  46. private static readonly int DEFAULT_BUF_SIZE = 20;
  47. private byte[] _data;
  48. private int _pos, _length;
  49. public _BytesIO([DefaultParameterValue(null)]object buffer) {
  50. __init__(buffer);
  51. }
  52. public void __init__([DefaultParameterValue(null)]object buffer) {
  53. if (Object.ReferenceEquals(_data, null)) {
  54. _data = new byte[DEFAULT_BUF_SIZE];
  55. }
  56. _pos = _length = 0;
  57. if (buffer != null) {
  58. DoWrite(buffer);
  59. _pos = 0;
  60. }
  61. }
  62. #endregion
  63. #region Public API
  64. /// <summary>
  65. /// close() -> None. Disable all I/O operations.
  66. /// </summary>
  67. public void close() {
  68. _data = null;
  69. }
  70. /// <summary>
  71. /// True if the file is closed.
  72. /// </summary>
  73. public bool closed {
  74. get {
  75. return _data == null;
  76. }
  77. }
  78. /// <summary>
  79. /// flush() -> None. Does nothing.
  80. /// </summary>
  81. public void flush() { }
  82. /// <summary>
  83. /// getvalue() -> bytes.
  84. ///
  85. /// Retrieve the entire contents of the BytesIO object.
  86. /// </summary>
  87. public Bytes getvalue() {
  88. EnsureOpen();
  89. if (_length == 0) {
  90. return Bytes.Empty;
  91. }
  92. byte[] arr = new byte[_length];
  93. Array.Copy(_data, arr, _length);
  94. return Bytes.Make(arr);
  95. }
  96. [Documentation("isatty() -> False\n\n"
  97. + "Always returns False since BytesIO objects are not connected\n"
  98. + "to a TTY-like device."
  99. )]
  100. public bool isatty() {
  101. EnsureOpen();
  102. return false;
  103. }
  104. [Documentation("read([size]) -> read at most size bytes, returned as a bytes object.\n\n"
  105. + "If the size argument is negative, read until EOF is reached.\n"
  106. + "Return an empty string at EOF."
  107. )]
  108. public Bytes read([DefaultParameterValue(-1)]int size) {
  109. EnsureOpen();
  110. int len = Math.Max(0, _length - _pos);
  111. if (size >= 0) {
  112. len = Math.Min(len, size);
  113. }
  114. if (len == 0) {
  115. return Bytes.Empty;
  116. }
  117. byte[] arr = new byte[len];
  118. Array.Copy(_data, _pos, arr, 0, len);
  119. _pos += len;
  120. return Bytes.Make(arr);
  121. }
  122. public Bytes read(object size) {
  123. if (size == null) {
  124. return read(-1);
  125. }
  126. EnsureOpen();
  127. throw PythonOps.TypeError("integer argument expected, got '{0}'", PythonTypeOps.GetName(size));
  128. }
  129. [Documentation("read1(size) -> read at most size bytes, returned as a bytes object.\n\n"
  130. + "If the size argument is negative or omitted, read until EOF is reached.\n"
  131. + "Return an empty string at EOF."
  132. )]
  133. public Bytes read1(int size) {
  134. return read(size);
  135. }
  136. public Bytes read1(object size) {
  137. return read(size);
  138. }
  139. public bool readable() {
  140. return true;
  141. }
  142. [Documentation("readinto(array_or_bytearray) -> int. Read up to len(b) bytes into b.\n\n"
  143. + "Returns number of bytes read (0 for EOF)."
  144. )]
  145. public int readinto([NotNull]ByteArray buffer) {
  146. EnsureOpen();
  147. int len = Math.Min(_length - _pos, buffer.Count);
  148. for (int i = 0; i < len; i++) {
  149. buffer[i] = _data[_pos++];
  150. }
  151. return len;
  152. }
  153. public int readinto([NotNull]ArrayModule.array buffer) {
  154. EnsureOpen();
  155. int len = Math.Min(_length - _pos, buffer.__len__() * buffer.itemsize);
  156. int tailLen = len % buffer.itemsize;
  157. buffer.FromStream(new MemoryStream(_data, _pos, len - tailLen, false, false), 0);
  158. _pos += len - tailLen;
  159. if (tailLen != 0) {
  160. byte[] tail = buffer.RawGetItem(len / buffer.itemsize);
  161. for (int i = 0; i < tailLen; i++) {
  162. tail[i] = _data[_pos++];
  163. }
  164. buffer.FromStream(new MemoryStream(tail), len / buffer.itemsize);
  165. }
  166. return len;
  167. }
  168. [Documentation("readline([size]) -> next line from the file, as bytes.\n\n"
  169. + "Retain newline. A non-negative size argument limits the maximum\n"
  170. + "number of bytes to return (an incomplete line may be returned then).\n"
  171. + "Return an empty string at EOF."
  172. )]
  173. public Bytes readline([DefaultParameterValue(-1)]int size) {
  174. EnsureOpen();
  175. if (_pos >= _length || size == 0) {
  176. return Bytes.Empty;
  177. }
  178. int origPos = _pos;
  179. while ((size < 0 || _pos - origPos < size) && _pos < _length) {
  180. if (_data[_pos] == '\n') {
  181. _pos++;
  182. break;
  183. }
  184. _pos++;
  185. }
  186. byte[] arr = new byte[_pos - origPos];
  187. Array.Copy(_data, origPos, arr, 0, _pos - origPos);
  188. return Bytes.Make(arr);
  189. }
  190. public Bytes readline(object size) {
  191. if (size == null) {
  192. return readline(-1);
  193. }
  194. EnsureOpen();
  195. throw PythonOps.TypeError("integer argument expected, got '{0}'", PythonTypeOps.GetName(size));
  196. }
  197. [Documentation("readlines([size]) -> list of bytes objects, each a line from the file.\n\n"
  198. + "Call readline() repeatedly and return a list of the lines so read.\n"
  199. + "The optional size argument, if given, is an approximate bound on the\n"
  200. + "total number of bytes in the lines returned."
  201. )]
  202. public List readlines([DefaultParameterValue(-1)]int size) {
  203. EnsureOpen();
  204. List lines = new List();
  205. for (Bytes line = readline(-1); line.Count > 0; line = readline(-1)) {
  206. lines.append(line);
  207. if (size > 0) {
  208. size -= line.Count;
  209. if (size <= 0) {
  210. break;
  211. }
  212. }
  213. }
  214. return lines;
  215. }
  216. public List readlines(object size) {
  217. if (size == null) {
  218. return readlines(-1);
  219. }
  220. EnsureOpen();
  221. throw PythonOps.TypeError("integer argument expected, got '{0}'", PythonTypeOps.GetName(size));
  222. }
  223. [Documentation("seek(pos, whence=0) -> int. Change stream position.\n\n"
  224. + "Seek to byte offset pos relative to position indicated by whence:\n"
  225. + " 0 Start of stream (the default). pos should be >= 0;\n"
  226. + " 1 Current position - pos may be negative;\n"
  227. + " 2 End of stream - pos usually negative.\n"
  228. + "Returns the new absolute position."
  229. )]
  230. public int seek(int pos, [DefaultParameterValue(0)]int whence) {
  231. EnsureOpen();
  232. switch (whence) {
  233. case 0:
  234. if (pos < 0) {
  235. throw PythonOps.ValueError("negative seek value {0}", pos);
  236. }
  237. _pos = pos;
  238. return _pos;
  239. case 1:
  240. _pos = Math.Max(0, _pos + pos);
  241. return _pos;
  242. case 2:
  243. _pos = Math.Max(0, _length + pos);
  244. return _pos;
  245. default:
  246. throw PythonOps.ValueError("invalid whence ({0}, should be 0, 1 or 2)", whence);
  247. }
  248. }
  249. public int seek(CodeContext/*!*/ context, object pos, [DefaultParameterValue(0)]object whence) {
  250. EnsureOpen();
  251. if (pos == null || whence == null) {
  252. throw PythonOps.TypeError("an integer is required");
  253. }
  254. int intPos;
  255. if (pos is int) {
  256. intPos = (int)pos;
  257. } else if (pos is Extensible<int>) {
  258. intPos = ((Extensible<int>)pos).Value;
  259. } else if (pos is BigInteger) {
  260. intPos = (int)(BigInteger)pos;
  261. } else if (pos is Extensible<BigInteger>) {
  262. intPos = (int)(((Extensible<BigInteger>)pos).Value);
  263. } else if (pos is double || pos is Extensible<double>) {
  264. throw PythonOps.TypeError("position argument must be an integer");
  265. } else if (PythonContext.GetContext(context).PythonOptions.Python30) {
  266. throw PythonOps.TypeError("'{0}' object cannot be interpreted as an integer", PythonTypeOps.GetOldName(pos));
  267. } else {
  268. throw PythonOps.TypeError("an integer is required");
  269. }
  270. if (whence is int) {
  271. return seek(intPos, (int)whence);
  272. } else if (whence is Extensible<int>) {
  273. return seek(intPos, ((Extensible<int>)pos).Value);
  274. }else if (whence is BigInteger) {
  275. return seek(intPos, (int)(BigInteger)whence);
  276. } else if (whence is Extensible<BigInteger>) {
  277. return seek(intPos, (int)(((Extensible<BigInteger>)whence).Value));
  278. } else if (whence is double || whence is Extensible<double>) {
  279. if (PythonContext.GetContext(context).PythonOptions.Python30) {
  280. throw PythonOps.TypeError("integer argument expected, got float");
  281. } else {
  282. PythonOps.Warn(context, PythonExceptions.DeprecationWarning, "integer argument expected, got float");
  283. return seek(intPos, Converter.ConvertToInt32(whence));
  284. }
  285. } else if (PythonContext.GetContext(context).PythonOptions.Python30) {
  286. throw PythonOps.TypeError("'{0}' object cannot be interpreted as an integer", PythonTypeOps.GetOldName(whence));
  287. } else {
  288. throw PythonOps.TypeError("an integer is required");
  289. }
  290. }
  291. public Boolean seekable() {
  292. return true;
  293. }
  294. [Documentation("tell() -> current file position, an integer")]
  295. public int tell() {
  296. EnsureOpen();
  297. return _pos;
  298. }
  299. [Documentation("truncate([size]) -> int. Truncate the file to at most size bytes.\n\n"
  300. + "Size defaults to the current file position, as returned by tell().\n"
  301. + "Returns the new size. Imply an absolute seek to the position size."
  302. )]
  303. public int truncate() {
  304. return truncate(_pos);
  305. }
  306. public int truncate(int size) {
  307. EnsureOpen();
  308. if (size < 0) {
  309. throw PythonOps.ValueError("negative size value {0}", size);
  310. }
  311. _length = Math.Min(_length, size);
  312. return seek(size, 0);
  313. }
  314. public int truncate(object size) {
  315. if (size == null) {
  316. return truncate();
  317. }
  318. EnsureOpen();
  319. throw PythonOps.TypeError("integer argument expected, got '{0}'", PythonTypeOps.GetName(size));
  320. }
  321. public bool writable() {
  322. return true;
  323. }
  324. [Documentation("write(bytes) -> int. Write bytes to file.\n\n"
  325. + "Return the number of bytes written."
  326. )]
  327. public int write(object bytes) {
  328. EnsureOpen();
  329. return DoWrite(bytes);
  330. }
  331. [Documentation("writelines(sequence_of_strings) -> None. Write strings to the file.\n\n"
  332. + "Note that newlines are not added. The sequence can be any iterable\n"
  333. + "object producing strings. This is equivalent to calling write() for\n"
  334. + "each string."
  335. )]
  336. public void writelines([NotNull]IEnumerable lines) {
  337. EnsureOpen();
  338. IEnumerator en = lines.GetEnumerator();
  339. while (en.MoveNext()) {
  340. DoWrite(en.Current);
  341. }
  342. }
  343. #endregion
  344. #region IDisposable methods
  345. void IDisposable.Dispose() {
  346. close();
  347. }
  348. #endregion
  349. #region IEnumerator methods
  350. private object _current = null;
  351. object IEnumerator.Current {
  352. get {
  353. EnsureOpen();
  354. return _current;
  355. }
  356. }
  357. bool IEnumerator.MoveNext() {
  358. Bytes line = readline(-1);
  359. if (line.Count == 0) {
  360. return false;
  361. }
  362. _current = line;
  363. return true;
  364. }
  365. void IEnumerator.Reset() {
  366. seek(0, 0);
  367. _current = null;
  368. }
  369. #endregion
  370. #region Private implementation details
  371. private int DoWrite(byte[] bytes) {
  372. if (bytes.Length == 0) {
  373. return 0;
  374. }
  375. EnsureSizeSetLength(_pos + bytes.Length);
  376. Array.Copy(bytes, 0, _data, _pos, bytes.Length);
  377. _pos += bytes.Length;
  378. return bytes.Length;
  379. }
  380. private int DoWrite(ICollection<byte> bytes) {
  381. int nbytes = bytes.Count;
  382. if (nbytes == 0) {
  383. return 0;
  384. }
  385. EnsureSizeSetLength(_pos + nbytes);
  386. bytes.CopyTo(_data, _pos);
  387. _pos += nbytes;
  388. return nbytes;
  389. }
  390. private int DoWrite(IEnumerable bytes) {
  391. int origPos = _pos;
  392. IEnumerator en = ((IEnumerable)bytes).GetEnumerator();
  393. if (en.MoveNext()) {
  394. byte b = ByteOps.GetByte(en.Current);
  395. EnsureSizeSetLength(_pos + 1);
  396. _data[_pos++] = b;
  397. } else {
  398. return 0;
  399. }
  400. while (en.MoveNext()) {
  401. byte b = ByteOps.GetByte(en.Current);
  402. EnsureSize(_pos + 1);
  403. _data[_pos++] = b;
  404. }
  405. _length = Math.Max(_length, _pos);
  406. return _pos - origPos;
  407. }
  408. private int DoWrite(object bytes) {
  409. if (bytes is byte[]) {
  410. return DoWrite((byte[])bytes);
  411. } else if (bytes is Bytes) {
  412. return DoWrite(((Bytes)bytes)._bytes);
  413. } else if (bytes is ArrayModule.array) {
  414. return DoWrite(((ArrayModule.array)bytes).ToByteArray());
  415. } else if (bytes is PythonBuffer) {
  416. return DoWrite(((PythonBuffer)bytes).ToString());
  417. } else if (bytes is ICollection<byte>) {
  418. return DoWrite((ICollection<byte>)bytes);
  419. } else if (bytes is string) {
  420. return DoWrite((IEnumerable)bytes);
  421. }
  422. throw PythonOps.TypeError("expected a readable buffer object");
  423. }
  424. private void EnsureOpen() {
  425. if (closed) {
  426. throw PythonOps.ValueError("I/O operation on closed file.");
  427. }
  428. }
  429. private void EnsureSize(int size) {
  430. Debug.Assert(size > 0);
  431. if (_data.Length < size) {
  432. if (size <= DEFAULT_BUF_SIZE) {
  433. size = DEFAULT_BUF_SIZE;
  434. } else {
  435. size = Math.Max(size, _data.Length * 2);
  436. }
  437. byte[] oldBuffer = _data;
  438. _data = new byte[size];
  439. Array.Copy(oldBuffer, _data, _length);
  440. }
  441. }
  442. private void EnsureSizeSetLength(int size) {
  443. Debug.Assert(size >= _pos);
  444. Debug.Assert(_length <= _data.Length);
  445. if (_data.Length < size) {
  446. // EnsureSize is guaranteed to resize, so we need not write any zeros here.
  447. EnsureSize(size);
  448. _length = size;
  449. return;
  450. }
  451. // _data[_pos:size] is about to be overwritten, so we only need to zero out _data[_length:_pos]
  452. while (_length < _pos) {
  453. _data[_length++] = 0;
  454. }
  455. _length = Math.Max(_length, size);
  456. }
  457. #endregion
  458. }
  459. }
  460. }