PageRenderTime 48ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/Languages/IronPython/IronPython.Modules/_io.cs

http://github.com/IronLanguages/main
C# | 3242 lines | 2631 code | 543 blank | 68 comment | 588 complexity | 168cc533ecd4451efb57ef8f12aec1b3 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception

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. * 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. #if FEATURE_CORE_DLR
  16. using System.Linq.Expressions;
  17. #else
  18. using Microsoft.Scripting.Ast;
  19. #endif
  20. #if FEATURE_NUMERICS
  21. using System.Numerics;
  22. #else
  23. using Microsoft.Scripting.Math;
  24. #endif
  25. using System;
  26. using System.Collections;
  27. using System.Collections.Generic;
  28. using System.Diagnostics;
  29. using System.Dynamic;
  30. using System.IO;
  31. using System.Runtime.CompilerServices;
  32. using System.Runtime.InteropServices;
  33. using System.Text;
  34. using Microsoft.Scripting;
  35. using Microsoft.Scripting.Runtime;
  36. using Microsoft.Scripting.Utils;
  37. using IronPython.Runtime;
  38. using IronPython.Runtime.Binding;
  39. using IronPython.Runtime.Exceptions;
  40. using IronPython.Runtime.Operations;
  41. using IronPython.Runtime.Types;
  42. [assembly: PythonModule("_io", typeof(IronPython.Modules.PythonIOModule))]
  43. namespace IronPython.Modules {
  44. public static partial class PythonIOModule {
  45. public const int DEFAULT_BUFFER_SIZE = 8192;
  46. private static readonly object _blockingIOErrorKey = new object();
  47. private static readonly object _unsupportedOperationKey = new object();
  48. [SpecialName]
  49. public static void PerformModuleReload(PythonContext/*!*/ context, PythonDictionary/*!*/ dict) {
  50. PythonType t = context.EnsureModuleException(
  51. _blockingIOErrorKey,
  52. PythonExceptions.IOError,
  53. typeof(BlockingIOError),
  54. dict,
  55. "BlockingIOError",
  56. "__builtin__",
  57. msg => new _BlockingIOErrorException(msg)
  58. );
  59. // this makes repr work correctly (gh878)
  60. t.IsSystemType = true;
  61. context.EnsureModuleException(
  62. _unsupportedOperationKey,
  63. new PythonType[] { PythonExceptions.ValueError, PythonExceptions.IOError },
  64. typeof(PythonExceptions.BaseException),
  65. dict,
  66. "UnsupportedOperation",
  67. "io"
  68. );
  69. }
  70. [PythonType]
  71. public class _IOBase : IDisposable, IEnumerator<object>, IEnumerable<object>, IWeakReferenceable, IDynamicMetaObjectProvider, IPythonExpandable {
  72. private bool _closed;
  73. internal CodeContext/*!*/ context;
  74. public _IOBase(CodeContext/*!*/ context) {
  75. this.context = context;
  76. }
  77. #region Public API
  78. public void __del__(CodeContext/*!*/ context) {
  79. close(context);
  80. }
  81. public _IOBase __enter__() {
  82. _checkClosed();
  83. return this;
  84. }
  85. public void __exit__(CodeContext/*!*/ context, params object[] excinfo) {
  86. close(context);
  87. }
  88. public void _checkClosed() {
  89. _checkClosed(null);
  90. }
  91. public void _checkClosed(string msg) {
  92. if (closed) {
  93. throw PythonOps.ValueError(msg ?? "I/O operation on closed file.");
  94. }
  95. }
  96. public void _checkReadable() {
  97. _checkReadable(null);
  98. }
  99. public void _checkReadable(string msg) {
  100. if (!readable(context)) {
  101. throw PythonOps.ValueError(msg ?? "File or stream is not readable.");
  102. }
  103. }
  104. public void _checkSeekable() {
  105. _checkSeekable(null);
  106. }
  107. public void _checkSeekable(string msg) {
  108. if (!seekable(context)) {
  109. throw PythonOps.ValueError(msg ?? "File or stream is not seekable.");
  110. }
  111. }
  112. public void _checkWritable() {
  113. _checkWritable(null);
  114. }
  115. public void _checkWritable(string msg) {
  116. if (!writable(context)) {
  117. throw PythonOps.ValueError(msg ?? "File or stream is not writable.");
  118. }
  119. }
  120. public virtual void close(CodeContext/*!*/ context) {
  121. try {
  122. if (!_closed) {
  123. flush(context);
  124. }
  125. } finally {
  126. _closed = true;
  127. }
  128. }
  129. public virtual bool closed {
  130. get { return _closed; }
  131. }
  132. public virtual int fileno(CodeContext/*!*/ context) {
  133. throw UnsupportedOperation(context, "fileno");
  134. }
  135. public virtual void flush(CodeContext/*!*/ context) {
  136. _checkClosed();
  137. }
  138. public virtual bool isatty(CodeContext/*!*/ context) {
  139. _checkClosed();
  140. return false;
  141. }
  142. [PythonHidden]
  143. public virtual Bytes peek(CodeContext/*!*/ context, [DefaultParameterValue(0)]int length) {
  144. _checkClosed();
  145. throw AttributeError("peek");
  146. }
  147. [PythonHidden]
  148. public virtual object read(CodeContext/*!*/ context, [DefaultParameterValue(null)]object length) {
  149. throw AttributeError("read");
  150. }
  151. [PythonHidden]
  152. public virtual Bytes read1(CodeContext/*!*/ context, [DefaultParameterValue(0)]int length) {
  153. throw AttributeError("read1");
  154. }
  155. public virtual bool readable(CodeContext/*!*/ context) {
  156. return false;
  157. }
  158. public virtual object readline(CodeContext/*!*/ context, int limit) {
  159. _checkClosed();
  160. List<Bytes> res = new List<Bytes>();
  161. int count = 0;
  162. while (limit < 0 || res.Count < limit) {
  163. object cur = read(context, 1);
  164. if (cur == null) {
  165. break;
  166. }
  167. Bytes curBytes = GetBytes(cur, "read()");
  168. if (curBytes.Count == 0) {
  169. break;
  170. }
  171. res.Add(curBytes);
  172. count += curBytes.Count;
  173. if (curBytes._bytes[curBytes.Count - 1] == (byte)'\n') {
  174. break;
  175. }
  176. }
  177. return Bytes.Concat(res, count);
  178. }
  179. public object readline(CodeContext/*!*/ context, [DefaultParameterValue(null)]object limit) {
  180. return readline(context, GetInt(limit, -1));
  181. }
  182. public virtual List readlines() {
  183. return readlines(null);
  184. }
  185. public virtual List readlines([DefaultParameterValue(null)]object hint) {
  186. int size = GetInt(hint, -1);
  187. List res = new List();
  188. if (size <= 0) {
  189. foreach (object line in this) {
  190. res.AddNoLock(line);
  191. }
  192. return res;
  193. }
  194. int count = 0;
  195. foreach (object line in this) {
  196. Bytes bytes = line as Bytes;
  197. if (bytes != null) {
  198. res.AddNoLock(line);
  199. count += bytes.Count;
  200. if (count >= size) {
  201. break;
  202. }
  203. continue;
  204. }
  205. string str = line as string;
  206. if (str != null) {
  207. res.AddNoLock(line);
  208. count += str.Length;
  209. if (count >= size) {
  210. break;
  211. }
  212. continue;
  213. }
  214. throw PythonOps.TypeError("next() should return string or bytes");
  215. }
  216. return res;
  217. }
  218. public virtual BigInteger seek(CodeContext/*!*/ context, BigInteger pos, [DefaultParameterValue(0)]object whence) {
  219. throw UnsupportedOperation(context, "seek");
  220. }
  221. public virtual bool seekable(CodeContext/*!*/ context) {
  222. return false;
  223. }
  224. public virtual BigInteger tell(CodeContext/*!*/ context) {
  225. return seek(context, 0, 1);
  226. }
  227. public virtual BigInteger truncate(CodeContext/*!*/ context, [DefaultParameterValue(null)]object pos) {
  228. throw UnsupportedOperation(context, "truncate");
  229. }
  230. public virtual bool writable(CodeContext/*!*/ context) {
  231. return false;
  232. }
  233. [PythonHidden]
  234. public virtual BigInteger write(CodeContext/*!*/ context, object buf) {
  235. throw AttributeError("write");
  236. }
  237. public virtual void writelines(CodeContext/*!*/ context, object lines) {
  238. _checkClosed();
  239. IEnumerator en = PythonOps.GetEnumerator(context, lines);
  240. while (en.MoveNext()) {
  241. write(context, en.Current);
  242. }
  243. }
  244. #endregion
  245. ~_IOBase() {
  246. try {
  247. close(context);
  248. } catch { }
  249. }
  250. #region IEnumerator<object> Members
  251. private object _current;
  252. object IEnumerator<object>.Current {
  253. get { return _current; }
  254. }
  255. #endregion
  256. #region IEnumerator Members
  257. object IEnumerator.Current {
  258. get { return _current; }
  259. }
  260. bool IEnumerator.MoveNext() {
  261. _current = readline(context, -1);
  262. if (_current == null) {
  263. return false;
  264. }
  265. Bytes bytes = _current as Bytes;
  266. if (bytes != null) {
  267. return bytes.Count > 0;
  268. }
  269. string str = _current as string;
  270. if (str != null) {
  271. return str.Length > 0;
  272. }
  273. return PythonOps.IsTrue(_current);
  274. }
  275. void IEnumerator.Reset() {
  276. _current = null;
  277. seek(context, 0, 0);
  278. }
  279. #endregion
  280. #region IEnumerable<object> Members
  281. [PythonHidden]
  282. public IEnumerator<object> GetEnumerator() {
  283. _checkClosed();
  284. return this;
  285. }
  286. #endregion
  287. #region IEnumerable Members
  288. IEnumerator IEnumerable.GetEnumerator() {
  289. _checkClosed();
  290. return this;
  291. }
  292. #endregion
  293. #region IDisposable Members
  294. void IDisposable.Dispose() { }
  295. #endregion
  296. #region IWeakReferenceable Members
  297. private WeakRefTracker _weakref;
  298. WeakRefTracker IWeakReferenceable.GetWeakRef() {
  299. return _weakref;
  300. }
  301. bool IWeakReferenceable.SetWeakRef(WeakRefTracker value) {
  302. _weakref = value;
  303. return true;
  304. }
  305. void IWeakReferenceable.SetFinalizer(WeakRefTracker value) {
  306. ((IWeakReferenceable)this).SetWeakRef(value);
  307. }
  308. #endregion
  309. #region IPythonExpandable Members
  310. private IDictionary<string, object> _customAttributes;
  311. IDictionary<string, object> IPythonExpandable.EnsureCustomAttributes() {
  312. return _customAttributes = new Dictionary<string, object>();
  313. }
  314. IDictionary<string, object> IPythonExpandable.CustomAttributes {
  315. get { return _customAttributes; }
  316. }
  317. CodeContext/*!*/ IPythonExpandable.Context {
  318. get { return context; }
  319. }
  320. #endregion
  321. #region IDynamicMetaObjectProvider Members
  322. DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) {
  323. return new MetaExpandable<_IOBase>(parameter, this);
  324. }
  325. #endregion
  326. #region Private implementation details
  327. internal Exception UnsupportedOperation(CodeContext/*!*/ context, string attr) {
  328. throw PythonExceptions.CreateThrowable(
  329. (PythonType)PythonContext.GetContext(context).GetModuleState(_unsupportedOperationKey),
  330. string.Format("{0}.{1} not supported", PythonTypeOps.GetName(this), attr)
  331. );
  332. }
  333. internal Exception AttributeError(string attrName) {
  334. throw PythonOps.AttributeError("'{0}' object has no attribute '{1}'", PythonTypeOps.GetName(this), attrName);
  335. }
  336. internal Exception InvalidPosition(BigInteger pos) {
  337. return PythonOps.IOError("Raw stream returned invalid position {0}", pos);
  338. }
  339. #endregion
  340. }
  341. [PythonType]
  342. public class _RawIOBase : _IOBase, IDynamicMetaObjectProvider {
  343. public _RawIOBase(CodeContext/*!*/ context) : base(context) { }
  344. #region Public API
  345. public override object read(CodeContext/*!*/ context, [DefaultParameterValue(null)]object size) {
  346. int sizeInt = GetInt(size, -1);
  347. if (sizeInt < 0) {
  348. return readall(context);
  349. }
  350. ByteArray arr = new ByteArray(new List<byte>(sizeInt));
  351. sizeInt = (int)readinto(context, arr);
  352. List<byte> res = arr._bytes;
  353. if (sizeInt < res.Count) {
  354. res.RemoveRange(sizeInt, res.Count - sizeInt);
  355. }
  356. return new Bytes(res);
  357. }
  358. public Bytes readall(CodeContext/*!*/ context) {
  359. List<Bytes> res = new List<Bytes>();
  360. int count = 0;
  361. for (; ; ) {
  362. object cur = read(context, DEFAULT_BUFFER_SIZE);
  363. if (cur == null) {
  364. break;
  365. }
  366. Bytes curBytes = GetBytes(cur, "read()");
  367. if (curBytes.Count == 0) {
  368. break;
  369. }
  370. count += curBytes.Count;
  371. res.Add(curBytes);
  372. }
  373. return Bytes.Concat(res, count);
  374. }
  375. public virtual BigInteger readinto(CodeContext/*!*/ context, object buf) {
  376. throw UnsupportedOperation(context, "readinto");
  377. }
  378. public override BigInteger write(CodeContext/*!*/ context, object buf) {
  379. throw UnsupportedOperation(context, "write");
  380. }
  381. #endregion
  382. #region IDynamicMetaObjectProvider Members
  383. DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) {
  384. return new MetaExpandable<_RawIOBase>(parameter, this);
  385. }
  386. #endregion
  387. }
  388. [PythonType]
  389. public class _BufferedIOBase : _IOBase, IDynamicMetaObjectProvider {
  390. public _BufferedIOBase(CodeContext/*!*/ context) : base(context) { }
  391. #region Public API
  392. public virtual object detach(CodeContext/*!*/ context) {
  393. throw UnsupportedOperation(context, "detach");
  394. }
  395. public override object read(CodeContext/*!*/ context, [DefaultParameterValue(null)]object length) {
  396. throw UnsupportedOperation(context, "read");
  397. }
  398. public virtual BigInteger readinto(CodeContext/*!*/ context, object buf) {
  399. int length = -1;
  400. if (PythonOps.HasAttr(context, buf, "__len__")) {
  401. length = PythonOps.Length(buf);
  402. }
  403. object dataObj = read(context, length);
  404. if (dataObj == null) {
  405. return BigInteger.Zero;
  406. }
  407. Bytes data = GetBytes(dataObj, "read()");
  408. IList<byte> bytes = buf as IList<byte>;
  409. if (bytes != null) {
  410. for (int i = 0; i < data.Count; i++) {
  411. bytes[i] = data._bytes[i];
  412. }
  413. GC.KeepAlive(this);
  414. return data.Count;
  415. }
  416. object setter;
  417. if (PythonOps.TryGetBoundAttr(buf, "__setslice__", out setter)) {
  418. PythonOps.CallWithContext(context, setter, new Slice(data.Count), data);
  419. GC.KeepAlive(this);
  420. return data.Count;
  421. }
  422. if (PythonOps.TryGetBoundAttr(buf, "__setitem__", out setter)) {
  423. for (int i = 0; i < data.Count; i++) {
  424. PythonOps.CallWithContext(context, setter, i, data[context, i]);
  425. }
  426. GC.KeepAlive(this);
  427. return data.Count;
  428. }
  429. throw PythonOps.TypeError("must be read-write buffer, not " + PythonTypeOps.GetName(buf));
  430. }
  431. public override BigInteger write(CodeContext/*!*/ context, object buf) {
  432. throw UnsupportedOperation(context, "write");
  433. }
  434. #endregion
  435. #region IDynamicMetaObjectProvider Members
  436. DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) {
  437. return new MetaExpandable<_BufferedIOBase>(parameter, this);
  438. }
  439. #endregion
  440. }
  441. [PythonType]
  442. public class _TextIOBase : _IOBase, IDynamicMetaObjectProvider {
  443. public _TextIOBase(CodeContext/*!*/ context) : base(context) { }
  444. #region Public API
  445. public virtual object detach(CodeContext/*!*/ context) {
  446. throw UnsupportedOperation(context, "detach");
  447. }
  448. public virtual string encoding {
  449. get { return null; }
  450. }
  451. public virtual string errors {
  452. get { return null; }
  453. }
  454. public virtual object newlines {
  455. get { return null; }
  456. }
  457. public override object read(CodeContext/*!*/ context, [DefaultParameterValue(-1)]object length) {
  458. throw UnsupportedOperation(context, "read");
  459. }
  460. public override object readline(CodeContext/*!*/ context, [DefaultParameterValue(-1)]int limit) {
  461. throw UnsupportedOperation(context, "readline");
  462. }
  463. public override BigInteger truncate(CodeContext/*!*/ context, [DefaultParameterValue(null)]object pos) {
  464. throw UnsupportedOperation(context, "truncate");
  465. }
  466. public override BigInteger write(CodeContext/*!*/ context, object str) {
  467. throw UnsupportedOperation(context, "write");
  468. }
  469. #endregion
  470. #region IDynamicMetaObjectProvider Members
  471. DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) {
  472. return new MetaExpandable<_TextIOBase>(parameter, this);
  473. }
  474. #endregion
  475. }
  476. [PythonType]
  477. public class BufferedReader : _BufferedIOBase, IDynamicMetaObjectProvider {
  478. private _IOBase _rawIO;
  479. private object _raw;
  480. private int _bufSize;
  481. private Bytes _readBuf;
  482. private int _readBufPos;
  483. internal static BufferedReader Create(CodeContext/*!*/ context, object raw, [DefaultParameterValue(DEFAULT_BUFFER_SIZE)]int buffer_size) {
  484. var res = new BufferedReader(context, raw, buffer_size);
  485. res.__init__(context, raw, buffer_size);
  486. return res;
  487. }
  488. public BufferedReader(
  489. CodeContext/*!*/ context,
  490. object raw,
  491. [DefaultParameterValue(DEFAULT_BUFFER_SIZE)]int buffer_size
  492. ) : base(context) {
  493. }
  494. public void __init__(
  495. CodeContext/*!*/ context,
  496. object raw,
  497. [DefaultParameterValue(DEFAULT_BUFFER_SIZE)]int buffer_size
  498. ) {
  499. this.raw = raw;
  500. if (_rawIO != null) {
  501. if (!_rawIO.readable(context)) {
  502. throw PythonOps.IOError("\"raw\" argument must be readable.");
  503. }
  504. } else {
  505. if (PythonOps.Not(PythonOps.Invoke(context, _raw, "readable"))) {
  506. throw PythonOps.IOError("\"raw\" argument must be readable.");
  507. }
  508. }
  509. if (buffer_size <= 0) {
  510. throw PythonOps.ValueError("invalid buffer size (must be positive)");
  511. }
  512. _bufSize = buffer_size;
  513. _readBuf = Bytes.Empty;
  514. }
  515. #region Public API
  516. public object raw {
  517. get {
  518. return _raw;
  519. }
  520. set {
  521. _rawIO = value as _IOBase;
  522. _raw = value;
  523. }
  524. }
  525. #region _BufferedIOMixin
  526. public override BigInteger truncate(CodeContext/*!*/ context, [DefaultParameterValue(null)]object pos) {
  527. if (_rawIO != null) {
  528. return _rawIO.truncate(context, pos);
  529. }
  530. return GetBigInt(
  531. PythonOps.Invoke(context, _raw, "truncate", pos),
  532. "truncate() should return integer"
  533. );
  534. }
  535. public override void close(CodeContext/*!*/ context) {
  536. if (!closed) {
  537. try {
  538. flush(context);
  539. } finally {
  540. if (_rawIO != null) {
  541. _rawIO.close(context);
  542. } else {
  543. PythonOps.Invoke(context, _raw, "close");
  544. }
  545. }
  546. }
  547. }
  548. public override object detach(CodeContext/*!*/ context) {
  549. if (_raw == null) {
  550. throw PythonOps.ValueError("raw stream already detached");
  551. }
  552. flush(context);
  553. object res = _raw;
  554. raw = null;
  555. return res;
  556. }
  557. public override bool seekable(CodeContext/*!*/ context) {
  558. if (_rawIO != null) {
  559. return _rawIO.seekable(context);
  560. }
  561. return PythonOps.IsTrue(PythonOps.Invoke(context, _raw, "seekable"));
  562. }
  563. public override bool readable(CodeContext/*!*/ context) {
  564. if (_rawIO != null) {
  565. return _rawIO.readable(context);
  566. }
  567. return PythonOps.IsTrue(PythonOps.Invoke(context, _raw, "readable"));
  568. }
  569. public override bool writable(CodeContext/*!*/ context) {
  570. if (_rawIO != null) {
  571. return _rawIO.writable(context);
  572. }
  573. return PythonOps.IsTrue(PythonOps.Invoke(context, _raw, "writable"));
  574. }
  575. public override bool closed {
  576. get {
  577. if (_rawIO != null) {
  578. return _rawIO.closed;
  579. }
  580. return PythonOps.IsTrue(PythonOps.GetBoundAttr(context, _raw, "closed"));
  581. }
  582. }
  583. public object name {
  584. get {
  585. return PythonOps.GetBoundAttr(context, _raw, "name");
  586. }
  587. }
  588. public object mode {
  589. get {
  590. return PythonOps.GetBoundAttr(context, _raw, "mode");
  591. }
  592. }
  593. public override int fileno(CodeContext/*!*/ context) {
  594. if (_rawIO != null) {
  595. return _rawIO.fileno(context);
  596. }
  597. return GetInt(
  598. PythonOps.Invoke(context, _raw, "fileno"),
  599. "fileno() should return integer"
  600. );
  601. }
  602. public override bool isatty(CodeContext/*!*/ context) {
  603. if (_rawIO != null) {
  604. return _rawIO.isatty(context);
  605. }
  606. return PythonOps.IsTrue(PythonOps.Invoke(context, _raw, "isatty"));
  607. }
  608. #endregion
  609. public override object read(CodeContext/*!*/ context, [DefaultParameterValue(null)]object length) {
  610. int len = GetInt(length, -1);
  611. if (len < -1) {
  612. throw PythonOps.ValueError("invalid number of bytes to read");
  613. }
  614. lock (this) {
  615. return ReadNoLock(context, len);
  616. }
  617. }
  618. private Bytes ReadNoLock(CodeContext/*!*/ context, int length) {
  619. if (length == 0) {
  620. return Bytes.Empty;
  621. }
  622. if (length < 0) {
  623. List<Bytes> chunks = new List<Bytes>();
  624. int count = 0;
  625. if (_readBuf.Count > 0) {
  626. chunks.Add(ResetReadBuf());
  627. count += chunks[0].Count;
  628. }
  629. for (; ; ) {
  630. object chunkObj;
  631. if (_rawIO != null) {
  632. chunkObj = _rawIO.read(context, -1);
  633. } else {
  634. chunkObj = PythonOps.Invoke(context, _raw, "read", -1);
  635. }
  636. Bytes chunk = GetBytes(chunkObj, "read()");
  637. if (chunk == null || chunk.Count == 0) {
  638. if (count == 0) {
  639. return chunk;
  640. }
  641. break;
  642. }
  643. chunks.Add(chunk);
  644. count += chunk.Count;
  645. }
  646. GC.KeepAlive(this);
  647. return Bytes.Concat(chunks, count);
  648. }
  649. if (length < _readBuf.Count - _readBufPos) {
  650. // requested data is already buffered
  651. byte[] res = new byte[length];
  652. Array.Copy(_readBuf._bytes, _readBufPos, res, 0, length);
  653. _readBufPos += length;
  654. if (_readBufPos == _readBuf.Count) {
  655. ResetReadBuf();
  656. }
  657. GC.KeepAlive(this);
  658. return Bytes.Make(res);
  659. } else {
  660. // a read is required to provide requested amount of data
  661. List<Bytes> chunks = new List<Bytes>();
  662. int remaining = length;
  663. if (_readBuf.Count > 0) {
  664. chunks.Add(ResetReadBuf());
  665. remaining -= chunks[0].Count;
  666. }
  667. while (remaining > 0) {
  668. object chunkObj;
  669. if (_rawIO != null) {
  670. chunkObj = _rawIO.read(context, _bufSize);
  671. } else {
  672. chunkObj = PythonOps.Invoke(context, _raw, "read", _bufSize);
  673. }
  674. Bytes chunk = chunkObj != null ? GetBytes(chunkObj, "read()") : Bytes.Empty;
  675. _readBuf = chunk;
  676. if (_readBuf.Count == 0) {
  677. break;
  678. }
  679. if (remaining >= _readBuf.Count - _readBufPos) {
  680. remaining -= _readBuf.Count - _readBufPos;
  681. chunks.Add(ResetReadBuf());
  682. } else {
  683. byte[] bytes = new byte[remaining];
  684. Array.Copy(_readBuf._bytes, 0, bytes, 0, remaining);
  685. chunks.Add(Bytes.Make(bytes));
  686. _readBufPos = remaining;
  687. remaining = 0;
  688. break;
  689. }
  690. }
  691. GC.KeepAlive(this);
  692. return Bytes.Concat(chunks, length - remaining);
  693. }
  694. }
  695. public override Bytes peek(CodeContext/*!*/ context, [DefaultParameterValue(0)]int length) {
  696. _checkClosed();
  697. if (length <= 0 || length > _bufSize) {
  698. length = _bufSize;
  699. }
  700. lock (this) {
  701. return PeekNoLock(context, length);
  702. }
  703. }
  704. private Bytes PeekNoLock(CodeContext/*!*/ context, int length) {
  705. int bufLen = _readBuf.Count - _readBufPos;
  706. byte[] bytes = new byte[length];
  707. if (length <= bufLen) {
  708. Array.Copy(_readBuf._bytes, _readBufPos, bytes, 0, length);
  709. return Bytes.Make(bytes);
  710. }
  711. object nextObj;
  712. if (_rawIO != null) {
  713. nextObj = _rawIO.read(context, length - _readBuf.Count + _readBufPos);
  714. } else {
  715. nextObj = PythonOps.Invoke(context, _raw, "read", length - _readBuf.Count + _readBufPos);
  716. }
  717. Bytes next = nextObj != null ? GetBytes(nextObj, "read()") : Bytes.Empty;
  718. _readBuf = ResetReadBuf() + next;
  719. return _readBuf;
  720. }
  721. public override Bytes read1(CodeContext/*!*/ context, [DefaultParameterValue(0)]int length) {
  722. if (length == 0) {
  723. return Bytes.Empty;
  724. } else if (length < 0) {
  725. throw PythonOps.ValueError("number of bytes to read must be positive");
  726. }
  727. lock (this) {
  728. PeekNoLock(context, 1);
  729. return ReadNoLock(context, Math.Min(length, _readBuf.Count - _readBufPos));
  730. }
  731. }
  732. public override BigInteger tell(CodeContext/*!*/ context) {
  733. BigInteger res = _rawIO != null ?
  734. _rawIO.tell(context) :
  735. GetBigInt(
  736. PythonOps.Invoke(context, _raw, "tell"),
  737. "tell() should return integer"
  738. );
  739. if (res < 0) {
  740. throw InvalidPosition(res);
  741. }
  742. return res - _readBuf.Count + _readBufPos;
  743. }
  744. public BigInteger seek(double offset, [DefaultParameterValue(0)]object whence) {
  745. _checkClosed();
  746. throw PythonOps.TypeError("an integer is required");
  747. }
  748. public override BigInteger seek(CodeContext/*!*/ context, BigInteger pos, [DefaultParameterValue(0)]object whence) {
  749. int whenceInt = GetInt(whence);
  750. if (whenceInt < 0 || whenceInt > 2) {
  751. throw PythonOps.ValueError("invalid whence ({0}, should be 0, 1, or 2)", whenceInt);
  752. }
  753. lock (this) {
  754. if (whenceInt == 1) {
  755. pos -= _readBuf.Count - _readBufPos;
  756. }
  757. object posObj;
  758. if (_rawIO != null) {
  759. posObj = _rawIO.seek(context, pos, whenceInt);
  760. } else {
  761. posObj = PythonOps.Invoke(context, _raw, "seek", whenceInt);
  762. }
  763. pos = GetBigInt(posObj, "seek() should return integer");
  764. ResetReadBuf();
  765. if (pos < 0) {
  766. throw InvalidPosition(pos);
  767. }
  768. GC.KeepAlive(this);
  769. return pos;
  770. }
  771. }
  772. #endregion
  773. #region IDynamicMetaObjectProvider Members
  774. DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) {
  775. return new MetaExpandable<BufferedReader>(parameter, this);
  776. }
  777. #endregion
  778. #region Private implementation details
  779. private Bytes ResetReadBuf() {
  780. Bytes res;
  781. if (_readBufPos == 0) {
  782. res = _readBuf;
  783. } else {
  784. byte[] bytes = new byte[_readBuf.Count - _readBufPos];
  785. Array.Copy(_readBuf._bytes, _readBufPos, bytes, 0, bytes.Length);
  786. res = Bytes.Make(bytes);
  787. _readBufPos = 0;
  788. }
  789. _readBuf = Bytes.Empty;
  790. return res;
  791. }
  792. #endregion
  793. }
  794. [PythonType]
  795. public class BufferedWriter : _BufferedIOBase, IDynamicMetaObjectProvider {
  796. private _IOBase _rawIO;
  797. private object _raw;
  798. private int _bufSize;
  799. private List<byte> _writeBuf;
  800. internal static BufferedWriter Create(CodeContext/*!*/ context,
  801. object raw,
  802. [DefaultParameterValue(DEFAULT_BUFFER_SIZE)]int buffer_size,
  803. [DefaultParameterValue(null)]object max_buffer_size) {
  804. var res = new BufferedWriter(context, raw, buffer_size, max_buffer_size);
  805. res.__init__(context, raw, buffer_size, max_buffer_size);
  806. return res;
  807. }
  808. public BufferedWriter(
  809. CodeContext/*!*/ context,
  810. object raw,
  811. [DefaultParameterValue(DEFAULT_BUFFER_SIZE)]int buffer_size,
  812. [DefaultParameterValue(null)]object max_buffer_size
  813. )
  814. : base(context) {
  815. }
  816. public void __init__(
  817. CodeContext/*!*/ context,
  818. object raw,
  819. [DefaultParameterValue(DEFAULT_BUFFER_SIZE)]int buffer_size,
  820. [DefaultParameterValue(null)]object max_buffer_size
  821. ) {
  822. if (max_buffer_size != null) {
  823. PythonOps.Warn(context, PythonExceptions.DeprecationWarning, "max_buffer_size is deprecated");
  824. }
  825. this.raw = raw;
  826. if (_rawIO != null) {
  827. if (!_rawIO.writable(context)) {
  828. throw PythonOps.IOError("\"raw\" argument must be writable.");
  829. }
  830. } else {
  831. if (PythonOps.Not(PythonOps.Invoke(context, _raw, "writable"))) {
  832. throw PythonOps.IOError("\"raw\" argument must be writable.");
  833. }
  834. }
  835. if (buffer_size <= 0) {
  836. throw PythonOps.ValueError("invalid buffer size (must be positive)");
  837. }
  838. _bufSize = buffer_size;
  839. _writeBuf = new List<byte>();
  840. }
  841. #region Public API
  842. public object raw {
  843. get {
  844. return _raw;
  845. }
  846. set {
  847. _rawIO = value as _IOBase;
  848. _raw = value;
  849. }
  850. }
  851. #region _BufferedIOMixin
  852. public override void close(CodeContext/*!*/ context) {
  853. if (!closed) {
  854. try {
  855. flush(context);
  856. } finally {
  857. if (_rawIO != null) {
  858. _rawIO.close(context);
  859. } else {
  860. PythonOps.Invoke(context, _raw, "close");
  861. }
  862. }
  863. }
  864. }
  865. public override object detach(CodeContext/*!*/ context) {
  866. if (_raw == null) {
  867. throw PythonOps.ValueError("raw stream already detached");
  868. }
  869. flush(context);
  870. object res = _raw;
  871. raw = null;
  872. return res;
  873. }
  874. public override bool seekable(CodeContext/*!*/ context) {
  875. if (_rawIO != null) {
  876. var res = _rawIO.seekable(context);
  877. GC.KeepAlive(this);
  878. return res;
  879. }
  880. return PythonOps.IsTrue(PythonOps.Invoke(context, _raw, "seekable"));
  881. }
  882. public override bool readable(CodeContext/*!*/ context) {
  883. if (_rawIO != null) {
  884. var res = _rawIO.readable(context);
  885. GC.KeepAlive(this);
  886. return res;
  887. }
  888. return PythonOps.IsTrue(PythonOps.Invoke(context, _raw, "readable"));
  889. }
  890. public override bool writable(CodeContext/*!*/ context) {
  891. if (_rawIO != null) {
  892. var res = _rawIO.writable(context);
  893. GC.KeepAlive(this);
  894. return res;
  895. }
  896. return PythonOps.IsTrue(PythonOps.Invoke(context, _raw, "writable"));
  897. }
  898. public override bool closed {
  899. get {
  900. if (_rawIO != null) {
  901. return _rawIO.closed;
  902. }
  903. return PythonOps.IsTrue(PythonOps.GetBoundAttr(context, _raw, "closed"));
  904. }
  905. }
  906. public object name {
  907. get {
  908. return PythonOps.GetBoundAttr(context, _raw, "name");
  909. }
  910. }
  911. public object mode {
  912. get {
  913. return PythonOps.GetBoundAttr(context, _raw, "mode");
  914. }
  915. }
  916. public override int fileno(CodeContext/*!*/ context) {
  917. if (_rawIO != null) {
  918. var res = _rawIO.fileno(context);
  919. GC.KeepAlive(this);
  920. return res;
  921. }
  922. return GetInt(
  923. PythonOps.Invoke(context, _raw, "fileno"),
  924. "fileno() should return integer"
  925. );
  926. }
  927. public override bool isatty(CodeContext/*!*/ context) {
  928. if (_rawIO != null) {
  929. var res = _rawIO.isatty(context);
  930. GC.KeepAlive(this);
  931. return res;
  932. }
  933. return PythonOps.IsTrue(PythonOps.Invoke(context, _raw, "isatty"));
  934. }
  935. #endregion
  936. public override BigInteger write(CodeContext/*!*/ context, object buf) {
  937. _checkClosed("write to closed file");
  938. IList<byte> bytes = GetBytes(buf);
  939. lock (this) {
  940. if (_writeBuf.Count > _bufSize) {
  941. FlushNoLock(context);
  942. }
  943. int count = _writeBuf.Count;
  944. _writeBuf.AddRange(bytes);
  945. count = _writeBuf.Count - count;
  946. if (_writeBuf.Count > _bufSize) {
  947. try {
  948. FlushNoLock(context);
  949. } catch (_BlockingIOErrorException) {
  950. if (_writeBuf.Count > _bufSize) {
  951. // do a partial write
  952. int extra = _writeBuf.Count - _bufSize;
  953. count -= extra;
  954. _writeBuf.RemoveRange(_bufSize, extra);
  955. }
  956. throw;
  957. }
  958. }
  959. return count;
  960. }
  961. }
  962. public override BigInteger truncate(CodeContext/*!*/ context, [DefaultParameterValue(null)]object pos) {
  963. lock (this) {
  964. FlushNoLock(context);
  965. if (pos == null) {
  966. if (_rawIO != null) {
  967. pos = _rawIO.tell(context);
  968. } else {
  969. pos = GetBigInt(
  970. PythonOps.Invoke(context, _raw, "tell"),
  971. "tell() should return integer"
  972. );
  973. }
  974. }
  975. if (_rawIO != null) {
  976. return _rawIO.truncate(context, pos);
  977. }
  978. var res = GetBigInt(
  979. PythonOps.Invoke(context, _raw, "truncate", pos),
  980. "truncate() should return integer"
  981. );
  982. GC.KeepAlive(this);
  983. return res;
  984. }
  985. }
  986. public override void flush(CodeContext/*!*/ context) {
  987. lock (this) {
  988. FlushNoLock(context);
  989. }
  990. }
  991. private void FlushNoLock(CodeContext/*!*/ context) {
  992. _checkClosed("flush of closed file");
  993. int count = 0;
  994. try {
  995. while (_writeBuf.Count > 0) {
  996. object writtenObj;
  997. if (_rawIO != null) {
  998. writtenObj = _rawIO.write(context, _writeBuf);
  999. } else {
  1000. writtenObj = PythonOps.Invoke(context, _raw, "write", _writeBuf);
  1001. }
  1002. int written = GetInt(writtenObj, "write() should return integer");
  1003. if (written > _writeBuf.Count || written < 0) {
  1004. throw PythonOps.IOError("write() returned incorrect number of bytes");
  1005. }
  1006. _writeBuf.RemoveRange(0, written);
  1007. count += written;
  1008. }
  1009. } catch (_BlockingIOErrorException e) {
  1010. object w;
  1011. int written;
  1012. if (!PythonOps.TryGetBoundAttr(e, "characters_written", out w) ||
  1013. !TryGetInt(w, out written)) {
  1014. throw;
  1015. }
  1016. _writeBuf.RemoveRange(0, written);
  1017. count += written;
  1018. throw;
  1019. }
  1020. }
  1021. public override BigInteger tell(CodeContext/*!*/ context) {
  1022. BigInteger res = _rawIO != null ?
  1023. _rawIO.tell(context) :
  1024. GetBigInt(
  1025. PythonOps.Invoke(context, _raw, "tell"),
  1026. "tell() should return integer"
  1027. );
  1028. if (res < 0) {
  1029. throw InvalidPosition(res);
  1030. }
  1031. GC.KeepAlive(this);
  1032. return res + _writeBuf.Count;
  1033. }
  1034. public BigInteger seek(double offset, [DefaultParameterValue(0)]object whence) {
  1035. _checkClosed();
  1036. throw PythonOps.TypeError("an integer is required");
  1037. }
  1038. public override BigInteger seek(CodeContext/*!*/ context, BigInteger pos, [DefaultParameterValue(0)]object whence) {
  1039. int whenceInt = GetInt(whence);
  1040. if (whenceInt < 0 || whenceInt > 2) {
  1041. throw PythonOps.ValueError("invalid whence ({0}, should be 0, 1, or 2)", whenceInt);
  1042. }
  1043. lock (this) {
  1044. FlushNoLock(context);
  1045. BigInteger res = _rawIO != null ?
  1046. _rawIO.seek(context, pos, whenceInt) :
  1047. res = GetBigInt(
  1048. PythonOps.Invoke(context, _raw, "seek", pos, whenceInt),
  1049. "seek() should return integer"
  1050. );
  1051. if (res < 0) {
  1052. throw InvalidPosition(pos);
  1053. }
  1054. GC.KeepAlive(this);
  1055. return res;
  1056. }
  1057. }
  1058. #endregion
  1059. #region IDynamicMetaObjectProvider Members
  1060. DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) {
  1061. return new MetaExpandable<BufferedWriter>(parameter, this);
  1062. }
  1063. #endregion
  1064. }
  1065. [PythonType]
  1066. public class BufferedRandom : _BufferedIOBase, IDynamicMetaObjectProvider {
  1067. private _IOBase _inner;
  1068. private int _bufSize;
  1069. private Bytes _readBuf;
  1070. private int _readBufPos;
  1071. private List<byte> _writeBuf;
  1072. internal static BufferedRandom Create(CodeContext/*!*/ context,
  1073. _IOBase raw,
  1074. [DefaultParameterValue(DEFAULT_BUFFER_SIZE)]int buffer_size,
  1075. [DefaultParameterValue(null)]object max_buffer_size) {
  1076. var res = new BufferedRandom(context, raw, buffer_size, max_buffer_size);
  1077. res.__init__(context, raw, buffer_size, max_buffer_size);
  1078. return res;
  1079. }
  1080. public BufferedRandom(
  1081. CodeContext/*!*/ context,
  1082. _IOBase raw,
  1083. [DefaultParameterValue(DEFAULT_BUFFER_SIZE)]int buffer_size,
  1084. [DefaultParameterValue(null)]object max_buffer_size
  1085. ) : base(context) {
  1086. }
  1087. public void __init__(
  1088. CodeContext/*!*/ context,
  1089. _IOBase raw,
  1090. [DefaultParameterValue(DEFAULT_BUFFER_SIZE)]int buffer_size,
  1091. [DefaultParameterValue(null)]object max_buffer_size
  1092. ) {
  1093. if (max_buffer_size != null) {
  1094. PythonOps.Warn(context, PythonExceptions.DeprecationWarning, "max_buffer_size is deprecated");
  1095. }
  1096. raw._checkSeekable();
  1097. if (buffer_size <= 0) {
  1098. throw PythonOps.ValueError("invalid buffer size (must be positive)");
  1099. } else if (!raw.readable(context)) {
  1100. throw PythonOps.IOError("\"raw\" argument must be readable.");
  1101. } else if (!raw.writable(context)) {
  1102. throw PythonOps.IOError("\"raw\" argument must be writable.");
  1103. }
  1104. _bufSize = buffer_size;
  1105. _inner = raw;
  1106. _readBuf = Bytes.Empty;
  1107. _writeBuf = new List<byte>();
  1108. }
  1109. #region Public API
  1110. public _IOBase raw {
  1111. get {
  1112. return _inner;
  1113. }
  1114. set {
  1115. _inner = value;
  1116. }
  1117. }
  1118. #region _BufferedIOMixin
  1119. public override void close(CodeContext/*!*/ context) {
  1120. if (!closed) {
  1121. try {
  1122. flush(context);
  1123. } finally {
  1124. _inner.close(context);
  1125. }
  1126. }
  1127. }
  1128. public override object detach(CodeContext/*!*/ context) {
  1129. if (_inner == null) {
  1130. throw PythonOps.ValueError("raw stream already detached");
  1131. }
  1132. flush(context);
  1133. _IOBase res = _inner;
  1134. _inner = null;
  1135. return res;
  1136. }
  1137. public override bool seekable(CodeContext/*!*/ context) {
  1138. var res = _inner.seekable(context);
  1139. GC.KeepAlive(this);
  1140. return res;
  1141. }
  1142. public override bool readable(CodeContext/*!*/ context) {
  1143. var res = _inner.readable(context);
  1144. GC.KeepAlive(this);
  1145. return res;
  1146. }
  1147. public override bool writable(CodeContext/*!*/ context) {
  1148. var res = _inner.writable(context);
  1149. GC.KeepAlive(this);
  1150. return res;
  1151. }
  1152. public override bool closed {
  1153. get { return _inner.closed; }
  1154. }
  1155. public object name {
  1156. get {
  1157. return PythonOps.GetBoundAttr(context, _inner, "name");
  1158. }
  1159. }
  1160. public object mode {
  1161. get {
  1162. return PythonOps.GetBoundAttr(context, _inner, "mode");
  1163. }
  1164. }
  1165. public override int fileno(CodeContext/*!*/ context) {
  1166. var res = _inner.fileno(context);

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