PageRenderTime 59ms CodeModel.GetById 20ms 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
  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);
  1167. GC.KeepAlive(this);
  1168. return res;
  1169. }
  1170. public override bool isatty(CodeContext/*!*/ context) {
  1171. return _inner.isatty(context);
  1172. }
  1173. #endregion
  1174. #region BufferedReader
  1175. public override object read(CodeContext/*!*/ context, [DefaultParameterValue(null)]object length) {
  1176. flush(context);
  1177. int len = GetInt(length, -1);
  1178. if (len < -1) {
  1179. throw PythonOps.ValueError("invalid number of bytes to read");
  1180. }
  1181. lock (this) {
  1182. return ReadNoLock(context, len);
  1183. }
  1184. }
  1185. private Bytes ReadNoLock(CodeContext/*!*/ context, int length) {
  1186. if (length == 0) {
  1187. return Bytes.Empty;
  1188. }
  1189. if (length < 0) {
  1190. List<Bytes> chunks = new List<Bytes>();
  1191. int count = 0;
  1192. if (_readBuf.Count > 0) {
  1193. chunks.Add(ResetReadBuf());
  1194. count += chunks[0].Count;
  1195. }
  1196. for (; ; ) {
  1197. Bytes chunk = (Bytes)_inner.read(context, -1);
  1198. if (chunk == null || chunk.Count == 0) {
  1199. if (count == 0) {
  1200. return chunk;
  1201. }
  1202. break;
  1203. }
  1204. chunks.Add(chunk);
  1205. count += chunk.Count;
  1206. }
  1207. GC.KeepAlive(this);
  1208. return Bytes.Concat(chunks, count);
  1209. }
  1210. if (length < _readBuf.Count - _readBufPos) {
  1211. // requested data is already buffered
  1212. byte[] res = new byte[length];
  1213. Array.Copy(_readBuf._bytes, _readBufPos, res, 0, length);
  1214. _readBufPos += length;
  1215. if (_readBufPos == _readBuf.Count) {
  1216. ResetReadBuf();
  1217. }
  1218. GC.KeepAlive(this);
  1219. return Bytes.Make(res);
  1220. } else {
  1221. // a read is required to provide requested amount of data
  1222. List<Bytes> chunks = new List<Bytes>();
  1223. int remaining = length;
  1224. if (_readBuf.Count > 0) {
  1225. chunks.Add(ResetReadBuf());
  1226. remaining -= chunks[0].Count;
  1227. }
  1228. while (remaining > 0) {
  1229. _readBuf = (Bytes)_inner.read(context, _bufSize) ?? Bytes.Empty;
  1230. if (_readBuf.Count == 0) {
  1231. break;
  1232. }
  1233. if (remaining >= _readBuf.Count - _readBufPos) {
  1234. remaining -= _readBuf.Count - _readBufPos;
  1235. chunks.Add(ResetReadBuf());
  1236. } else {
  1237. byte[] bytes = new byte[remaining];
  1238. Array.Copy(_readBuf._bytes, 0, bytes, 0, remaining);
  1239. chunks.Add(Bytes.Make(bytes));
  1240. _readBufPos = remaining;
  1241. remaining = 0;
  1242. break;
  1243. }
  1244. }
  1245. GC.KeepAlive(this);
  1246. return Bytes.Concat(chunks, length - remaining);
  1247. }
  1248. }
  1249. public override Bytes peek(CodeContext/*!*/ context, [DefaultParameterValue(0)]int length) {
  1250. _checkClosed();
  1251. flush(context);
  1252. if (length <= 0 || length > _bufSize) {
  1253. length = _bufSize;
  1254. }
  1255. lock (this) {
  1256. return PeekNoLock(context, length);
  1257. }
  1258. }
  1259. private Bytes PeekNoLock(CodeContext/*!*/ context, int length) {
  1260. int bufLen = _readBuf.Count - _readBufPos;
  1261. byte[] bytes = new byte[length];
  1262. if (length <= bufLen) {
  1263. Array.Copy(_readBuf._bytes, _readBufPos, bytes, 0, length);
  1264. return Bytes.Make(bytes);
  1265. }
  1266. Bytes next = (Bytes)_inner.read(context, length - _readBuf.Count + _readBufPos) ?? Bytes.Empty;
  1267. _readBuf = ResetReadBuf() + next;
  1268. GC.KeepAlive(this);
  1269. return _readBuf;
  1270. }
  1271. public override Bytes read1(CodeContext/*!*/ context, [DefaultParameterValue(0)]int length) {
  1272. flush(context);
  1273. if (length == 0) {
  1274. return Bytes.Empty;
  1275. } else if (length < 0) {
  1276. throw PythonOps.ValueError("number of bytes to read must be positive");
  1277. }
  1278. lock (this) {
  1279. PeekNoLock(context, 1);
  1280. return ReadNoLock(context, Math.Min(length, _readBuf.Count - _readBufPos));
  1281. }
  1282. }
  1283. #region Private implementation details
  1284. private Bytes ResetReadBuf() {
  1285. Bytes res;
  1286. if (_readBufPos == 0) {
  1287. res = _readBuf;
  1288. } else {
  1289. byte[] bytes = new byte[_readBuf.Count - _readBufPos];
  1290. Array.Copy(_readBuf._bytes, _readBufPos, bytes, 0, bytes.Length);
  1291. res = Bytes.Make(bytes);
  1292. _readBufPos = 0;
  1293. }
  1294. _readBuf = Bytes.Empty;
  1295. return res;
  1296. }
  1297. #endregion
  1298. #endregion
  1299. #region BufferedWriter
  1300. public override BigInteger write(CodeContext/*!*/ context, object buf) {
  1301. _checkClosed("write to closed file");
  1302. // undo any read-ahead
  1303. if (_readBuf.Count > 0) {
  1304. lock (this) {
  1305. _inner.seek(context, _readBufPos - _readBuf.Count, 1);
  1306. ResetReadBuf();
  1307. }
  1308. }
  1309. IList<byte> bytes = GetBytes(buf);
  1310. lock (this) {
  1311. if (_writeBuf.Count > _bufSize) {
  1312. FlushNoLock(context);
  1313. }
  1314. int count = _writeBuf.Count;
  1315. _writeBuf.AddRange(bytes);
  1316. count = _writeBuf.Count - count;
  1317. if (_writeBuf.Count > _bufSize) {
  1318. try {
  1319. FlushNoLock(context);
  1320. } catch (_BlockingIOErrorException) {
  1321. if (_writeBuf.Count > _bufSize) {
  1322. // do a partial write
  1323. int extra = _writeBuf.Count - _bufSize;
  1324. count -= extra;
  1325. _writeBuf.RemoveRange(_bufSize, extra);
  1326. }
  1327. throw;
  1328. }
  1329. }
  1330. return count;
  1331. }
  1332. }
  1333. public override void flush(CodeContext/*!*/ context) {
  1334. lock (this) {
  1335. FlushNoLock(context);
  1336. }
  1337. }
  1338. private void FlushNoLock(CodeContext/*!*/ context) {
  1339. _checkClosed("flush of closed file");
  1340. int count = 0;
  1341. try {
  1342. while (_writeBuf.Count > 0) {
  1343. int written = (int)_inner.write(context, _writeBuf);
  1344. if (written > _writeBuf.Count || written < 0) {
  1345. throw PythonOps.IOError("write() returned incorrect number of bytes");
  1346. }
  1347. _writeBuf.RemoveRange(0, written);
  1348. count += written;
  1349. }
  1350. } catch (_BlockingIOErrorException e) {
  1351. object w;
  1352. int written;
  1353. if (!PythonOps.TryGetBoundAttr(e, "characters_written", out w) ||
  1354. !TryGetInt(w, out written)) {
  1355. throw;
  1356. }
  1357. _writeBuf.RemoveRange(0, written);
  1358. count += written;
  1359. throw;
  1360. }
  1361. }
  1362. #endregion
  1363. public override BigInteger readinto(CodeContext/*!*/ context, object buf) {
  1364. flush(context);
  1365. return base.readinto(context, buf);
  1366. }
  1367. public BigInteger seek(double offset, [DefaultParameterValue(0)]object whence) {
  1368. _checkClosed();
  1369. throw PythonOps.TypeError("an integer is required");
  1370. }
  1371. public override BigInteger seek(CodeContext/*!*/ context, BigInteger pos, [DefaultParameterValue(0)]object whence) {
  1372. int whenceInt = GetInt(whence);
  1373. if (whenceInt < 0 || whenceInt > 2) {
  1374. throw PythonOps.ValueError("invalid whence ({0}, should be 0, 1, or 2)", whenceInt);
  1375. }
  1376. lock (this) {
  1377. FlushNoLock(context);
  1378. // undo any read-ahead
  1379. if (_readBuf.Count > 0) {
  1380. _inner.seek(context, _readBufPos - _readBuf.Count, 1);
  1381. }
  1382. pos = _inner.seek(context, pos, whence);
  1383. ResetReadBuf();
  1384. if (pos < 0) {
  1385. throw PythonOps.IOError("seek() returned invalid position");
  1386. }
  1387. GC.KeepAlive(this);
  1388. return pos;
  1389. }
  1390. }
  1391. public override BigInteger truncate(CodeContext/*!*/ context, [DefaultParameterValue(null)]object pos) {
  1392. lock (this) {
  1393. FlushNoLock(context);
  1394. if (pos == null) {
  1395. pos = tell(context);
  1396. }
  1397. var res = _inner.truncate(context, pos);
  1398. GC.KeepAlive(this);
  1399. return res;
  1400. }
  1401. }
  1402. public override BigInteger tell(CodeContext/*!*/ context) {
  1403. BigInteger res = _inner.tell(context);
  1404. if (res < 0) {
  1405. throw InvalidPosition(res);
  1406. }
  1407. if (_writeBuf.Count > 0) {
  1408. return res + _writeBuf.Count;
  1409. } else {
  1410. return res - _readBuf.Count + _readBufPos;
  1411. }
  1412. }
  1413. #endregion
  1414. #region IDynamicMetaObjectProvider Members
  1415. DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) {
  1416. return new MetaExpandable<BufferedRandom>(parameter, this);
  1417. }
  1418. #endregion
  1419. }
  1420. [PythonType]
  1421. public class BufferedRWPair : _BufferedIOBase, IDynamicMetaObjectProvider {
  1422. private BufferedReader _reader;
  1423. private BufferedWriter _writer;
  1424. public BufferedRWPair(
  1425. CodeContext/*!*/ context,
  1426. object reader,
  1427. object writer,
  1428. [DefaultParameterValue(DEFAULT_BUFFER_SIZE)]int buffer_size,
  1429. [DefaultParameterValue(null)]object max_buffer_size
  1430. ) : base(context) {
  1431. }
  1432. public void __init__(
  1433. CodeContext/*!*/ context,
  1434. object reader,
  1435. object writer,
  1436. [DefaultParameterValue(DEFAULT_BUFFER_SIZE)]int buffer_size,
  1437. [DefaultParameterValue(null)]object max_buffer_size
  1438. ) {
  1439. if (max_buffer_size != null) {
  1440. PythonOps.Warn(context, PythonExceptions.DeprecationWarning, "max_buffer_size is deprecated");
  1441. }
  1442. this.reader = reader;
  1443. this.writer = writer;
  1444. if (!_reader.readable(context)) {
  1445. throw PythonOps.IOError("\"reader\" object must be readable.");
  1446. }
  1447. if (!_writer.writable(context)) {
  1448. throw PythonOps.IOError("\"writer\" object must be writable.");
  1449. }
  1450. }
  1451. #region Public API
  1452. public object reader {
  1453. get { return _reader; }
  1454. set {
  1455. BufferedReader reader = value as BufferedReader;
  1456. if (reader == null) {
  1457. reader = BufferedReader.Create(context, value, DEFAULT_BUFFER_SIZE);
  1458. }
  1459. _reader = reader;
  1460. }
  1461. }
  1462. public object writer {
  1463. get { return _writer; }
  1464. set {
  1465. BufferedWriter writer = value as BufferedWriter;
  1466. if (writer == null) {
  1467. writer = BufferedWriter.Create(context, value, DEFAULT_BUFFER_SIZE, null);
  1468. }
  1469. _writer = writer;
  1470. }
  1471. }
  1472. public override object read(CodeContext/*!*/ context, [DefaultParameterValue(null)]object length) {
  1473. var res = _reader.read(context, length);
  1474. GC.KeepAlive(this);
  1475. return res;
  1476. }
  1477. public override BigInteger readinto(CodeContext/*!*/ context, object buf) {
  1478. var res = _reader.readinto(context, buf);
  1479. GC.KeepAlive(this);
  1480. return res;
  1481. }
  1482. public override BigInteger write(CodeContext/*!*/ context, object buf) {
  1483. var res = _writer.write(context, buf);
  1484. GC.KeepAlive(this);
  1485. return res;
  1486. }
  1487. public override Bytes peek(CodeContext/*!*/ context, [DefaultParameterValue(0)]int length) {
  1488. var res = _reader.peek(context, length);
  1489. GC.KeepAlive(this);
  1490. return res;
  1491. }
  1492. public override Bytes read1(CodeContext/*!*/ context, int length) {
  1493. var res = _reader.read1(context, length);
  1494. GC.KeepAlive(this);
  1495. return res;
  1496. }
  1497. public override bool readable(CodeContext/*!*/ context) {
  1498. var res = _reader.readable(context);
  1499. GC.KeepAlive(this);
  1500. return res;
  1501. }
  1502. public override bool writable(CodeContext/*!*/ context) {
  1503. var res = _writer.writable(context);
  1504. GC.KeepAlive(this);
  1505. return res;
  1506. }
  1507. public override void flush(CodeContext/*!*/ context) {
  1508. _writer.flush(context);
  1509. GC.KeepAlive(this);
  1510. }
  1511. public override void close(CodeContext/*!*/ context) {
  1512. try {
  1513. _writer.close(context);
  1514. } finally {
  1515. _reader.close(context);
  1516. }
  1517. GC.KeepAlive(this);
  1518. }
  1519. public override bool isatty(CodeContext/*!*/ context) {
  1520. var res = _reader.isatty(context) || _writer.isatty(context);
  1521. GC.KeepAlive(this);
  1522. return res;
  1523. }
  1524. public override bool closed {
  1525. get {
  1526. return _writer.closed;
  1527. }
  1528. }
  1529. #endregion
  1530. #region IDynamicMetaObjectProvider Members
  1531. DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) {
  1532. return new MetaExpandable<BufferedRWPair>(parameter, this);
  1533. }
  1534. #endregion
  1535. }
  1536. [PythonType]
  1537. public class StringIO : TextIOWrapper, IDynamicMetaObjectProvider {
  1538. public StringIO(
  1539. CodeContext/*!*/ context,
  1540. [DefaultParameterValue("")]string initial_value,
  1541. [DefaultParameterValue("\n")]string newline
  1542. ) : base(context) {
  1543. }
  1544. public void __init__(
  1545. CodeContext/*!*/ context,
  1546. [DefaultParameterValue("")]string initial_value,
  1547. [DefaultParameterValue("\n")]string newline
  1548. ) {
  1549. var buf = new BytesIO(context);
  1550. buf.__init__(null);
  1551. base.__init__(context, buf, "utf-8", null, newline, false);
  1552. if (newline == null) {
  1553. _writeTranslate = false;
  1554. }
  1555. if (!string.IsNullOrEmpty(initial_value)) {
  1556. write(context, initial_value);
  1557. seek(context, 0, 0);
  1558. }
  1559. }
  1560. #region Public API
  1561. public override object detach(CodeContext/*!*/ context) {
  1562. // doesn't make sense on StringIO
  1563. throw UnsupportedOperation(context, "detach");
  1564. }
  1565. public string getvalue(CodeContext/*!*/ context) {
  1566. flush(context);
  1567. return ((BytesIO)(object)_bufferTyped).getvalue().decode(context, _encoding, _errors);
  1568. }
  1569. #endregion
  1570. #region IDynamicMetaObjectProvider Members
  1571. DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) {
  1572. return new MetaExpandable<StringIO>(parameter, this);
  1573. }
  1574. #endregion
  1575. }
  1576. [PythonType]
  1577. public class TextIOWrapper : _TextIOBase, IEnumerator<object>, IEnumerable<object>, ICodeFormattable, IDynamicMetaObjectProvider {
  1578. public int _CHUNK_SIZE = 128;
  1579. internal _BufferedIOBase _bufferTyped;
  1580. private object _buffer;
  1581. internal string _encoding, _errors;
  1582. private bool _seekable, _telling;
  1583. private object _encoder, _decoder;
  1584. private bool _line_buffering;
  1585. private bool _readUniversal;
  1586. private bool _readTranslate;
  1587. internal bool _writeTranslate;
  1588. private string _readNL, _writeNL;
  1589. private int _decodedCharsUsed;
  1590. private string _decodedChars;
  1591. // snapshots: Used for accurate tell() and seek() behavior for multibyte codecs.
  1592. // _nextInput, if not null, is the chunk of input bytes that comes after the
  1593. // snapshot point. _decodeFlags is used to reconstruct the decoder state.
  1594. private Bytes _nextInput;
  1595. private int _decodeFlags;
  1596. internal TextIOWrapper(CodeContext/*!*/ context) : base(context) { }
  1597. internal static TextIOWrapper Create(CodeContext/*!*/ context,
  1598. object buffer,
  1599. [DefaultParameterValue(null)]string encoding,
  1600. [DefaultParameterValue(null)]string errors,
  1601. [DefaultParameterValue(null)]string newline,
  1602. [DefaultParameterValue(false)]bool line_buffering) {
  1603. var res = new TextIOWrapper(context, buffer, encoding, errors, newline, line_buffering);
  1604. res.__init__(context, buffer, encoding, errors, newline, line_buffering);
  1605. return res;
  1606. }
  1607. public TextIOWrapper(
  1608. CodeContext/*!*/ context,
  1609. object buffer,
  1610. [DefaultParameterValue(null)]string encoding,
  1611. [DefaultParameterValue(null)]string errors,
  1612. [DefaultParameterValue(null)]string newline,
  1613. [DefaultParameterValue(false)]bool line_buffering
  1614. ) : base(context) {
  1615. }
  1616. public void __init__(
  1617. CodeContext/*!*/ context,
  1618. object buffer,
  1619. [DefaultParameterValue(null)]string encoding,
  1620. [DefaultParameterValue(null)]string errors,
  1621. [DefaultParameterValue(null)]string newline,
  1622. [DefaultParameterValue(false)]bool line_buffering
  1623. ) {
  1624. switch(newline) {
  1625. case null:
  1626. case "":
  1627. case "\n":
  1628. case "\r":
  1629. case "\r\n":
  1630. break;
  1631. default:
  1632. throw PythonOps.ValueError(string.Format("illegal newline value: " + newline));
  1633. }
  1634. if (encoding == null) {
  1635. encoding = PythonLocale.PreferredEncoding;
  1636. if (encoding == "") {
  1637. encoding = "ascii";
  1638. }
  1639. }
  1640. if (errors == null) {
  1641. errors = "strict";
  1642. }
  1643. _bufferTyped = buffer as _BufferedIOBase;
  1644. _buffer = buffer;
  1645. _encoding = encoding;
  1646. _errors = errors;
  1647. _seekable = _telling = _bufferTyped != null ?
  1648. _bufferTyped.seekable(context) :
  1649. PythonOps.IsTrue(PythonOps.Invoke(context, _buffer, "seekable"));
  1650. _line_buffering = line_buffering;
  1651. _readUniversal = string.IsNullOrEmpty(newline);
  1652. _readTranslate = newline == null;
  1653. _readNL = newline;
  1654. _writeTranslate = newline != "";
  1655. _writeNL = string.IsNullOrEmpty(newline) ? System.Environment.NewLine : newline;
  1656. _decodedChars = "";
  1657. _decodedCharsUsed = 0;
  1658. }
  1659. #region Public API
  1660. public object buffer {
  1661. get {
  1662. return _buffer;
  1663. }
  1664. }
  1665. public override string encoding {
  1666. get { return _encoding; }
  1667. }
  1668. public override string errors {
  1669. get { return _errors; }
  1670. }
  1671. public bool line_buffering {
  1672. get { return _line_buffering; }
  1673. }
  1674. public override object newlines {
  1675. get {
  1676. if (_readUniversal && _decoder != null) {
  1677. IncrementalNewlineDecoder typedDecoder = _decoder as IncrementalNewlineDecoder;
  1678. if (typedDecoder != null) {
  1679. return typedDecoder.newlines;
  1680. } else {
  1681. return PythonOps.GetBoundAttr(context, _decoder, "newlines");
  1682. }
  1683. }
  1684. return null;
  1685. }
  1686. }
  1687. public override bool seekable(CodeContext/*!*/ context) {
  1688. return _seekable;
  1689. }
  1690. public override bool readable(CodeContext/*!*/ context) {
  1691. return _bufferTyped != null ?
  1692. _bufferTyped.readable(context) :
  1693. PythonOps.IsTrue(PythonOps.Invoke(context, _buffer, "readable"));
  1694. }
  1695. public override bool writable(CodeContext/*!*/ context) {
  1696. return _bufferTyped != null ?
  1697. _bufferTyped.writable(context) :
  1698. PythonOps.IsTrue(PythonOps.Invoke(context, _buffer, "writable"));
  1699. }
  1700. public override void flush(CodeContext/*!*/ context) {
  1701. if (_bufferTyped != null) {
  1702. _bufferTyped.flush(context);
  1703. } else {
  1704. PythonOps.Invoke(context, _buffer, "flush");
  1705. }
  1706. _telling = _seekable;
  1707. }
  1708. public override void close(CodeContext/*!*/ context) {
  1709. if (!closed) {
  1710. try {
  1711. flush(context);
  1712. } finally {
  1713. if (_bufferTyped != null) {
  1714. _bufferTyped.close(context);
  1715. } else {
  1716. PythonOps.Invoke(context, _buffer, "close");
  1717. }
  1718. }
  1719. }
  1720. }
  1721. public override bool closed {
  1722. get {
  1723. return _bufferTyped != null ?
  1724. _bufferTyped.closed :
  1725. PythonOps.IsTrue(
  1726. PythonOps.GetBoundAttr(context, _buffer, "closed")
  1727. );
  1728. }
  1729. }
  1730. public object name {
  1731. get {
  1732. return PythonOps.GetBoundAttr(context, _buffer, "name");
  1733. }
  1734. }
  1735. public override int fileno(CodeContext/*!*/ context) {
  1736. return _bufferTyped != null ?
  1737. _bufferTyped.fileno(context) :
  1738. GetInt(
  1739. PythonOps.Invoke(context, _buffer, "fileno"),
  1740. "fileno() should return an int"
  1741. );
  1742. }
  1743. public override bool isatty(CodeContext/*!*/ context) {
  1744. return _bufferTyped != null ?
  1745. _bufferTyped.isatty(context) :
  1746. PythonOps.IsTrue(PythonOps.Invoke(context, _buffer, "isatty"));
  1747. }
  1748. public override BigInteger write(CodeContext/*!*/ context, object s) {
  1749. string str = s as string;
  1750. if (str == null) {
  1751. Extensible<string> es = s as Extensible<string>;
  1752. if (es == null) {
  1753. throw PythonOps.TypeError("must be unicode, not {0}", PythonTypeOps.GetName(s));
  1754. }
  1755. str = es.Value;
  1756. }
  1757. if (closed) {
  1758. throw PythonOps.ValueError("write to closed file");
  1759. }
  1760. int length = str.Length;
  1761. bool hasLF = (_writeTranslate || _line_buffering) && str.Contains("\n");
  1762. if (hasLF && _writeTranslate && _writeNL != "\n") {
  1763. str = str.Replace("\n", _writeNL);
  1764. }
  1765. str = StringOps.encode(context, str, _encoding, _errors);
  1766. if (_bufferTyped != null) {
  1767. _bufferTyped.write(context, str);
  1768. } else {
  1769. PythonOps.Invoke(context, _buffer, "write", str);
  1770. }
  1771. if (_line_buffering && (hasLF || str.Contains("\r"))) {
  1772. flush(context);
  1773. }
  1774. _nextInput = null;
  1775. if (_decoder != null) {
  1776. PythonOps.Invoke(context, _decoder, "reset");
  1777. }
  1778. GC.KeepAlive(this);
  1779. return length;
  1780. }
  1781. public override BigInteger tell(CodeContext/*!*/ context) {
  1782. if (!_seekable) {
  1783. throw PythonOps.IOError("underlying stream is not seekable");
  1784. }
  1785. if (!_telling) {
  1786. throw PythonOps.IOError("telling position disabled by next() call");
  1787. }
  1788. flush(context);
  1789. BigInteger pos = _bufferTyped != null ?
  1790. _bufferTyped.tell(context) :
  1791. GetBigInt(
  1792. PythonOps.Invoke(context, _buffer, "tell"),
  1793. "tell() should return an integer"
  1794. );
  1795. if (pos < 0) {
  1796. throw InvalidPosition(pos);
  1797. }
  1798. object decoder = _decoder;
  1799. if (decoder == null || _nextInput == null) {
  1800. if (!string.IsNullOrEmpty(_decodedChars)) {
  1801. throw PythonOps.AssertionError("pending decoded text");
  1802. }
  1803. return pos;
  1804. }
  1805. IncrementalNewlineDecoder typedDecoder = decoder as IncrementalNewlineDecoder;
  1806. // skip backwards to snapshot point
  1807. pos -= _nextInput.Count;
  1808. // determine number of decoded chars used up after snapshot
  1809. int skip = _decodedCharsUsed;
  1810. if (skip == 0) {
  1811. return pos;
  1812. }
  1813. // start at snapshot point and run the decoder until we have enough chars
  1814. PythonTuple state;
  1815. if (typedDecoder != null) {
  1816. state = typedDecoder.getstate(context);
  1817. } else {
  1818. state = (PythonTuple)PythonOps.Invoke(context, decoder, "getstate");
  1819. }
  1820. try {
  1821. // keep track of starting position
  1822. if (typedDecoder != null) {
  1823. typedDecoder.SetState(context, Bytes.Empty, _decodeFlags);
  1824. } else {
  1825. PythonOps.Invoke(context, decoder, "setstate", PythonTuple.MakeTuple(Bytes.Empty, _decodeFlags));
  1826. }
  1827. BigInteger startPos = pos;
  1828. int bytesFed = 0;
  1829. int charsDecoded = 0;
  1830. // Feed the decoder one byte at a time while keeping track of the most recent
  1831. // safe position for snapshotting, i.e. a position in the file where the
  1832. // decoder's buffer is empty, allowing seek() to safely start advancing from
  1833. // there.
  1834. foreach (byte nextByte in _nextInput._bytes) {
  1835. Bytes next = new Bytes(new byte[] { nextByte });
  1836. bytesFed++;
  1837. if (typedDecoder != null) {
  1838. charsDecoded += typedDecoder.decode(context, next, false).Length;
  1839. } else {
  1840. charsDecoded += ((string)PythonOps.Invoke(context, decoder, "decode", next)).Length;
  1841. }
  1842. Bytes decodeBuffer;
  1843. if (typedDecoder != null) {
  1844. typedDecoder.GetState(context, out decodeBuffer, out _decodeFlags);
  1845. } else {
  1846. PythonTuple tuple = (PythonTuple)PythonOps.Invoke(context, decoder, "getstate");
  1847. decodeBuffer = GetBytes(tuple[0], "getstate");
  1848. _decodeFlags = Converter.ConvertToInt32(tuple[1]);
  1849. }
  1850. if ((decodeBuffer == null || decodeBuffer.Count == 0) && charsDecoded <= skip) {
  1851. // safe starting point
  1852. startPos += bytesFed;
  1853. skip -= charsDecoded;
  1854. bytesFed = 0;
  1855. charsDecoded = 0;
  1856. }
  1857. if (charsDecoded >= skip) {
  1858. // not enough decoded data; signal EOF for more
  1859. if (typedDecoder != null) {
  1860. charsDecoded += typedDecoder.decode(context, Bytes.Empty, true).Length;
  1861. } else {
  1862. charsDecoded += ((string)PythonOps.Invoke(context, decoder, "decode", Bytes.Empty, true)).Length;
  1863. }
  1864. if (charsDecoded < skip) {
  1865. throw PythonOps.IOError("can't reconstruct logical file position");
  1866. }
  1867. break;
  1868. }
  1869. }
  1870. return startPos;
  1871. } finally {
  1872. if (typedDecoder != null) {
  1873. typedDecoder.setstate(context, state);
  1874. } else {
  1875. PythonOps.Invoke(context, decoder, "setstate", state);
  1876. }
  1877. }
  1878. }
  1879. public override BigInteger truncate(CodeContext/*!*/ context, [DefaultParameterValue(null)]object pos) {
  1880. flush(context);
  1881. if (pos == null) {
  1882. pos = tell(context);
  1883. }
  1884. BigInteger position;
  1885. if (pos is int) {
  1886. position = (int)pos;
  1887. } else if (pos is BigInteger) {
  1888. position = (BigInteger)pos;
  1889. } else if (!Converter.TryConvertToBigInteger(pos, out position)) {
  1890. throw PythonOps.TypeError("an integer is required");
  1891. }
  1892. var savePos = tell(context);
  1893. seek(context, position, 0);
  1894. var ret = _bufferTyped != null ?
  1895. _bufferTyped.truncate(context, null) :
  1896. GetBigInt(
  1897. PythonOps.Invoke(context, _buffer, "truncate"),
  1898. "truncate() should return an integer"
  1899. );
  1900. seek(context, savePos, 0);
  1901. return ret;
  1902. }
  1903. public override object detach(CodeContext/*!*/ context) {
  1904. if (_buffer == null) {
  1905. throw PythonOps.ValueError("buffer is already detached");
  1906. }
  1907. flush(context);
  1908. object res = _bufferTyped ?? _buffer;
  1909. _buffer = _bufferTyped = null;
  1910. return res;
  1911. }
  1912. public BigInteger seek(double offset, [DefaultParameterValue(0)]object whence) {
  1913. _checkClosed();
  1914. throw PythonOps.TypeError("an integer is required");
  1915. }
  1916. public override BigInteger seek(CodeContext/*!*/ context, BigInteger cookie, [DefaultParameterValue(0)]object whence) {
  1917. int whenceInt = GetInt(whence);
  1918. if (closed) {
  1919. throw PythonOps.ValueError("tell on closed file");
  1920. }
  1921. if (!_seekable) {
  1922. throw PythonOps.IOError("underlying stream is not seekable");
  1923. }
  1924. IncrementalNewlineDecoder typedDecoder;
  1925. if (whenceInt == 1) {
  1926. // seek relative to the current position
  1927. if (cookie != 0) {
  1928. throw PythonOps.IOError("can't do nonzero cur-relative seeks");
  1929. }
  1930. whenceInt = 0;
  1931. cookie = tell(context);
  1932. } else if (whenceInt == 2) {
  1933. // seek relative to the end of the stream
  1934. if (cookie != 0) {
  1935. throw PythonOps.IOError("can't do nonzero end-relative seeks");
  1936. }
  1937. flush(context);
  1938. BigInteger pos = _bufferTyped != null ?
  1939. _bufferTyped.seek(context, BigInteger.Zero, 2) :
  1940. GetBigInt(
  1941. PythonOps.Invoke(context, _buffer, "seek", BigInteger.Zero, 2),
  1942. "seek() should return an integer"
  1943. );
  1944. if (pos < 0) {
  1945. throw InvalidPosition(pos);
  1946. }
  1947. SetDecodedChars(string.Empty);
  1948. _nextInput = null;
  1949. if (_decoder != null) {
  1950. typedDecoder = _decoder as IncrementalNewlineDecoder;
  1951. if (typedDecoder != null) {
  1952. typedDecoder.reset(context);
  1953. } else {
  1954. PythonOps.Invoke(context, _decoder, "reset");
  1955. }
  1956. }
  1957. GC.KeepAlive(this);
  1958. return pos;
  1959. }
  1960. if (whenceInt != 0) {
  1961. throw PythonOps.ValueError("invalid whence ({0}, should be 0, 1, or 2)", whenceInt);
  1962. }
  1963. if (cookie < 0) {
  1964. throw PythonOps.ValueError("negative seek position {0}", cookie);
  1965. }
  1966. flush(context);
  1967. // seek() works by going back to a safe starting point and replaying read(skip)
  1968. BigInteger startPos;
  1969. int decodeFlags;
  1970. int bytesFed;
  1971. int skip;
  1972. bool needEOF;
  1973. UnpackCookie(cookie, out startPos, out decodeFlags, out bytesFed, out skip, out needEOF);
  1974. // seek to safe starting point
  1975. if (_bufferTyped != null) {
  1976. _bufferTyped.seek(context, startPos, 0);
  1977. } else {
  1978. PythonOps.Invoke(context, _buffer, "seek", startPos, 0);
  1979. }
  1980. SetDecodedChars(string.Empty);
  1981. _nextInput = null;
  1982. // set decoder's state at starting point
  1983. object decoder = _decoder;
  1984. typedDecoder = decoder as IncrementalNewlineDecoder;
  1985. if (cookie == BigInteger.Zero && decoder != null) {
  1986. if (typedDecoder != null) {
  1987. typedDecoder.reset(context);
  1988. } else {
  1989. PythonOps.Invoke(context, decoder, "reset");
  1990. }
  1991. } else if (decoder != null || decodeFlags != 0 || skip != 0) {
  1992. if (_decoder == null) {
  1993. decoder = GetDecoder(context);
  1994. typedDecoder = decoder as IncrementalNewlineDecoder;
  1995. }
  1996. if (typedDecoder != null) {
  1997. typedDecoder.SetState(context, Bytes.Empty, decodeFlags);
  1998. } else {
  1999. PythonOps.Invoke(context, decoder, "setstate", PythonTuple.MakeTuple(Bytes.Empty, decodeFlags));
  2000. }
  2001. _decodeFlags = decodeFlags;
  2002. _nextInput = Bytes.Empty;
  2003. }
  2004. if (skip > 0) {
  2005. // similar to ReadChunk(); feed the decoder and save a snapshot
  2006. object chunkObj = _bufferTyped != null ?
  2007. _bufferTyped.read(context, bytesFed) :
  2008. PythonOps.Invoke(context, _buffer, "read", bytesFed);
  2009. Bytes chunk = chunkObj != null ? GetBytes(chunkObj, "read()") : Bytes.Empty;
  2010. if (typedDecoder != null) {
  2011. SetDecodedChars(typedDecoder.decode(context, chunk, needEOF));
  2012. } else {
  2013. SetDecodedChars((string)PythonOps.Invoke(context, decoder, "decode", chunk, needEOF));
  2014. }
  2015. // skip appropriate number of decoded chars
  2016. if (_decodedChars.Length < skip) {
  2017. throw PythonOps.IOError("can't restore logical file position");
  2018. }
  2019. _decodedCharsUsed = skip;
  2020. }
  2021. // reset the encoder for proper BOM handling
  2022. try {
  2023. object encoder = _encoder ?? GetEncoder(context);
  2024. if (cookie == 0) {
  2025. PythonOps.Invoke(context, encoder, "reset");
  2026. } else {
  2027. PythonOps.Invoke(context, encoder, "setstate", 0);
  2028. }
  2029. } catch (LookupException) {
  2030. // the encoder may not exist
  2031. }
  2032. GC.KeepAlive(this);
  2033. return cookie;
  2034. }
  2035. public override object read(CodeContext/*!*/ context, [DefaultParameterValue(null)]object length) {
  2036. _checkClosed();
  2037. if (!readable(context)) {
  2038. throw PythonOps.IOError("not readable");
  2039. }
  2040. int size = GetInt(length, -1);
  2041. object decoder = _decoder ?? GetDecoder(context);
  2042. if (size < 0) {
  2043. string res = GetDecodedChars();
  2044. object next = _bufferTyped != null ?
  2045. _bufferTyped.read(context, -1) :
  2046. PythonOps.Invoke(context, _buffer, "read", -1);
  2047. object decodeFunc = PythonOps.GetBoundAttr(context, decoder, "decode");
  2048. string decoded = (string)PythonOps.CallWithKeywordArgs(
  2049. context,
  2050. decodeFunc,
  2051. new object[] { next, true },
  2052. new string[] { "final" }
  2053. );
  2054. SetDecodedChars(string.Empty);
  2055. _nextInput = null;
  2056. if (res == null) {
  2057. res = decoded;
  2058. } else {
  2059. res += decoded;
  2060. }
  2061. return res;
  2062. } else {
  2063. StringBuilder res = new StringBuilder(GetDecodedChars(size));
  2064. bool notEof = true;
  2065. while (res.Length < size && notEof) {
  2066. notEof = ReadChunk(context);
  2067. res.Append(GetDecodedChars(size - res.Length));
  2068. }
  2069. return res.ToString();
  2070. }
  2071. }
  2072. public override object readline(CodeContext/*!*/ context, [DefaultParameterValue(-1)]int limit) {
  2073. _checkClosed("read from closed file");
  2074. string line = GetDecodedChars();
  2075. int start = 0;
  2076. if (_decoder == null) {
  2077. GetDecoder(context);
  2078. }
  2079. int pos, endPos;
  2080. for (; ; ) {
  2081. if (_readTranslate) {
  2082. // Newlines have already been translated into "\n"
  2083. pos = line.IndexOf('\n', start);
  2084. if (pos >= 0) {
  2085. endPos = pos + 1;
  2086. break;
  2087. }
  2088. start = line.Length;
  2089. } else if (_readUniversal) {
  2090. // Search for any newline, "\r" and/or "\n". The decoder ensures that
  2091. // "\r\n" isn't split up.
  2092. int nlPos = line.IndexOfAny(new char[] { '\r', '\n' }, start);
  2093. if (nlPos == -1) {
  2094. // no newlines found
  2095. start = line.Length;
  2096. } else if (line[nlPos] == '\n') {
  2097. // "\n" newline found
  2098. endPos = nlPos + 1;
  2099. break;
  2100. } else if (line.Length > nlPos + 1 && line[nlPos + 1] == '\n') {
  2101. // "\r\n" newline found
  2102. endPos = nlPos + 2;
  2103. break;
  2104. } else {
  2105. // "\r" newline found
  2106. endPos = nlPos + 1;
  2107. break;
  2108. }
  2109. } else {
  2110. // Non-universal newlines
  2111. pos = line.IndexOf(_readNL);
  2112. if (pos >= 0) {
  2113. endPos = pos + _readNL.Length;
  2114. break;
  2115. }
  2116. }
  2117. if (limit >= 0 && line.Length >= limit) {
  2118. endPos = limit;
  2119. break;
  2120. }
  2121. while (ReadChunk(context) && string.IsNullOrEmpty(_decodedChars)) { }
  2122. if (!string.IsNullOrEmpty(_decodedChars)) {
  2123. line += GetDecodedChars();
  2124. } else {
  2125. // EOF
  2126. SetDecodedChars(string.Empty);
  2127. _nextInput = null;
  2128. return line;
  2129. }
  2130. }
  2131. if (limit >= 0 && endPos > limit) {
  2132. endPos = limit;
  2133. }
  2134. // rewind to just after the line ending
  2135. RewindDecodedChars(line.Length - endPos);
  2136. GC.KeepAlive(this);
  2137. return line.Substring(0, endPos);
  2138. }
  2139. #endregion
  2140. #region IEnumerator<object> Members
  2141. private object _current;
  2142. object IEnumerator<object>.Current {
  2143. get { return _current; }
  2144. }
  2145. #endregion
  2146. #region IEnumerator Members
  2147. object IEnumerator.Current {
  2148. get { return _current; }
  2149. }
  2150. bool IEnumerator.MoveNext() {
  2151. _telling = false;
  2152. _current = readline(context, -1);
  2153. Bytes bytes;
  2154. string str;
  2155. bool res = _current != null && (
  2156. (bytes = _current as Bytes) != null && bytes.Count > 0 ||
  2157. (str = _current as string) != null && str.Length > 0 ||
  2158. PythonOps.IsTrue(_current)
  2159. );
  2160. if (!res) {
  2161. _nextInput = null;
  2162. _telling = _seekable;
  2163. }
  2164. return res;
  2165. }
  2166. void IEnumerator.Reset() {
  2167. _current = null;
  2168. seek(context, 0, 0);
  2169. }
  2170. #endregion
  2171. #region IEnumerable<object> Members
  2172. IEnumerator<object> IEnumerable<object>.GetEnumerator() {
  2173. _checkClosed();
  2174. return this;
  2175. }
  2176. #endregion
  2177. #region IEnumerable Members
  2178. IEnumerator IEnumerable.GetEnumerator() {
  2179. _checkClosed();
  2180. return this;
  2181. }
  2182. #endregion
  2183. #region ICodeFormattable Members
  2184. public string __repr__(CodeContext/*!*/ context) {
  2185. return string.Format("<_io.TextIOWrapper encoding='{0}'>", _encoding);
  2186. }
  2187. #endregion
  2188. #region IDynamicMetaObjectProvider Members
  2189. DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) {
  2190. return new MetaExpandable<TextIOWrapper>(parameter, this);
  2191. }
  2192. #endregion
  2193. #region Private implementation details
  2194. private void UnpackCookie(BigInteger cookie, out BigInteger pos, out int decodeFlags, out int bytesFed, out int skip, out bool needEOF) {
  2195. BigInteger mask = (BigInteger.One << 64) - 1;
  2196. pos = cookie & mask;
  2197. cookie >>= 64;
  2198. decodeFlags = (int)(cookie & mask);
  2199. cookie >>= 64;
  2200. bytesFed = (int)(cookie & mask);
  2201. cookie >>= 64;
  2202. skip = (int)(cookie & mask);
  2203. needEOF = cookie > mask;
  2204. }
  2205. private object GetEncoder(CodeContext/*!*/ context) {
  2206. object lookup = PythonOps.LookupEncoding(context, _encoding);
  2207. object factory;
  2208. if (lookup == null || !PythonOps.TryGetBoundAttr(context, lookup, "incrementalencoder", out factory)) {
  2209. throw PythonOps.LookupError(_encoding);
  2210. }
  2211. _encoder = PythonOps.CallWithContext(context, factory, _errors);
  2212. return _encoder;
  2213. }
  2214. private object GetDecoder(CodeContext/*!*/ context) {
  2215. object lookup = PythonOps.LookupEncoding(context, _encoding);
  2216. object factory;
  2217. if (lookup == null || !PythonOps.TryGetBoundAttr(context, lookup, "incrementaldecoder", out factory)) {
  2218. throw PythonOps.LookupError(_encoding);
  2219. }
  2220. _decoder = PythonOps.CallWithContext(context, factory, _errors);
  2221. if (_readUniversal) {
  2222. _decoder = new IncrementalNewlineDecoder(_decoder, _readTranslate, "strict");
  2223. }
  2224. return _decoder;
  2225. }
  2226. private void SetDecodedChars(string chars) {
  2227. _decodedChars = chars;
  2228. _decodedCharsUsed = 0;
  2229. }
  2230. private string GetDecodedChars() {
  2231. Debug.Assert(_decodedCharsUsed <= _decodedChars.Length);
  2232. string res = _decodedChars.Substring(_decodedCharsUsed);
  2233. _decodedCharsUsed += res.Length;
  2234. return res;
  2235. }
  2236. private string GetDecodedChars(int length) {
  2237. Debug.Assert(_decodedCharsUsed <= _decodedChars.Length);
  2238. length = Math.Min(length, _decodedChars.Length - _decodedCharsUsed);
  2239. string res = _decodedChars.Substring(_decodedCharsUsed, length);
  2240. _decodedCharsUsed += length;
  2241. return res;
  2242. }
  2243. private void RewindDecodedChars(int length) {
  2244. if (_decodedCharsUsed < length) {
  2245. throw PythonOps.AssertionError("rewind decoded_chars out of bounds");
  2246. }
  2247. _decodedCharsUsed -= length;
  2248. }
  2249. /// <summary>
  2250. /// Read and decode the next chunk from the buffered reader. Returns true if EOF was
  2251. /// not reached. Places decoded string in _decodedChars.
  2252. /// </summary>
  2253. private bool ReadChunk(CodeContext/*!*/ context) {
  2254. if (_decoder == null) {
  2255. throw PythonOps.ValueError("no decoder");
  2256. }
  2257. IncrementalNewlineDecoder typedDecoder = _decoder as IncrementalNewlineDecoder;
  2258. Bytes decodeBuffer = null;
  2259. int decodeFlags = 0;
  2260. if (_telling) {
  2261. // take a snapshot where the decoder's input buffer is empty
  2262. if (typedDecoder != null) {
  2263. typedDecoder.GetState(context, out decodeBuffer, out decodeFlags);
  2264. } else {
  2265. PythonTuple tuple = (PythonTuple)PythonOps.Invoke(context, _decoder, "getstate");
  2266. decodeBuffer = GetBytes(tuple[0], "getstate");
  2267. decodeFlags = (int)tuple[1];
  2268. }
  2269. }
  2270. object chunkObj = _bufferTyped != null ?
  2271. _bufferTyped.read(context, _CHUNK_SIZE) :
  2272. PythonOps.Invoke(context, _buffer, "read", _CHUNK_SIZE);
  2273. Bytes chunk = chunkObj != null ? GetBytes(chunkObj, "read()") : Bytes.Empty;
  2274. bool eof = chunkObj == null || chunk.Count == 0;
  2275. string decoded;
  2276. if (typedDecoder != null) {
  2277. decoded = typedDecoder.decode(context, chunk, eof);
  2278. } else {
  2279. decoded = (string)PythonOps.Invoke(context, _decoder, "decode", chunk, eof);
  2280. }
  2281. SetDecodedChars(decoded);
  2282. if (_telling) {
  2283. _decodeFlags = decodeFlags;
  2284. _nextInput = decodeBuffer + chunk;
  2285. }
  2286. return !eof;
  2287. }
  2288. #endregion
  2289. }
  2290. public static _IOBase open(
  2291. CodeContext/*!*/ context,
  2292. object file,
  2293. [DefaultParameterValue("r")]string mode,
  2294. [DefaultParameterValue(-1)]int buffering,
  2295. [DefaultParameterValue(null)]string encoding,
  2296. [DefaultParameterValue(null)]string errors,
  2297. [DefaultParameterValue(null)]string newline,
  2298. [DefaultParameterValue(true)]bool closefd
  2299. ) {
  2300. int fd = -1;
  2301. string fname = file as string;
  2302. if (fname == null) {
  2303. if (file is Extensible<string>) {
  2304. fname = ((Extensible<string>)file).Value;
  2305. } else {
  2306. fd = GetInt(file, 0);
  2307. }
  2308. }
  2309. HashSet<char> modes = MakeSet(mode);
  2310. if (modes.Count < mode.Length || !_validModes.IsSupersetOf(modes)) {
  2311. throw PythonOps.ValueError("invalid mode: {0}", mode);
  2312. }
  2313. bool reading = modes.Contains('r');
  2314. bool writing = modes.Contains('w');
  2315. bool appending = modes.Contains('a');
  2316. bool updating = modes.Contains('+');
  2317. bool text = modes.Contains('t');
  2318. bool binary = modes.Contains('b');
  2319. if (modes.Contains('U')) {
  2320. if (writing || appending) {
  2321. throw PythonOps.ValueError("can't use U and writing mode at once");
  2322. }
  2323. reading = true;
  2324. }
  2325. if (text && binary) {
  2326. throw PythonOps.ValueError("can't have text and binary mode at once");
  2327. }
  2328. if (reading && writing || reading && appending || writing && appending) {
  2329. throw PythonOps.ValueError("can't have read/write/append mode at once");
  2330. }
  2331. if (!(reading || writing || appending)) {
  2332. throw PythonOps.ValueError("must have exactly one of read/write/append mode");
  2333. }
  2334. if (binary && encoding != null) {
  2335. throw PythonOps.ValueError("binary mode doesn't take an encoding argument");
  2336. }
  2337. if (binary && newline != null) {
  2338. throw PythonOps.ValueError("binary mode doesn't take a newline argument");
  2339. }
  2340. mode = reading ? "r" : "";
  2341. if (writing) {
  2342. mode += 'w';
  2343. }
  2344. if (appending) {
  2345. mode += 'a';
  2346. }
  2347. if (updating) {
  2348. mode += '+';
  2349. }
  2350. FileIO fio;
  2351. if (fname != null) {
  2352. fio = new FileIO(context, fname, mode, closefd);
  2353. } else {
  2354. fio = new FileIO(context, fd, mode, closefd);
  2355. }
  2356. bool line_buffering = false;
  2357. if (buffering == 1 || buffering < 0 && fio.isatty(context)) {
  2358. buffering = -1;
  2359. line_buffering = true;
  2360. }
  2361. if (buffering < 0) {
  2362. buffering = DEFAULT_BUFFER_SIZE;
  2363. }
  2364. if (buffering == 0) {
  2365. if (binary) {
  2366. return fio;
  2367. }
  2368. throw PythonOps.ValueError("can't have unbuffered text I/O");
  2369. }
  2370. _BufferedIOBase buffer;
  2371. if (updating) {
  2372. buffer = BufferedRandom.Create(context, fio, buffering, null);
  2373. } else if (writing || appending) {
  2374. buffer = BufferedWriter.Create(context, fio, buffering, null);
  2375. } else if (reading) {
  2376. buffer = BufferedReader.Create(context, fio, buffering);
  2377. } else {
  2378. throw PythonOps.ValueError("unknown mode: {0}", mode);
  2379. }
  2380. if (binary) {
  2381. return buffer;
  2382. }
  2383. TextIOWrapper res = TextIOWrapper.Create(context, buffer, encoding, errors, newline, line_buffering);
  2384. ((IPythonExpandable)res).EnsureCustomAttributes()["mode"] = mode;
  2385. return res;
  2386. }
  2387. [PythonType]
  2388. public class IncrementalNewlineDecoder {
  2389. [Flags]
  2390. private enum LineEnding {
  2391. None = 0,
  2392. CR = 1,
  2393. LF = 2,
  2394. CRLF = 4,
  2395. All = CR | LF | CRLF
  2396. }
  2397. private object _decoder;
  2398. private bool _translate;
  2399. private LineEnding _seenNL;
  2400. private bool _pendingCR;
  2401. #pragma warning disable 414 // TODO: unused field
  2402. private string _errors;
  2403. #pragma warning restore 414
  2404. public IncrementalNewlineDecoder(object decoder, bool translate, [DefaultParameterValue("strict")]string errors) {
  2405. _decoder = decoder;
  2406. _translate = translate;
  2407. _errors = errors;
  2408. }
  2409. public string decode(CodeContext/*!*/ context, [NotNull]IList<byte> input, [DefaultParameterValue(false)]bool final) {
  2410. object output;
  2411. if (_decoder == null) {
  2412. output = input.MakeString();
  2413. } else {
  2414. output = PythonOps.CallWithKeywordArgs(
  2415. context,
  2416. PythonOps.GetBoundAttr(context, _decoder, "decode"),
  2417. new object[] { input, true },
  2418. new string[] { "final" }
  2419. );
  2420. }
  2421. string decoded = output as string;
  2422. if (decoded == null) {
  2423. if (output is Extensible<string>) {
  2424. decoded = ((Extensible<string>)output).Value;
  2425. } else {
  2426. throw PythonOps.TypeError("decoder produced {0}, expected str", PythonTypeOps.GetName(output));
  2427. }
  2428. }
  2429. return DecodeWorker(context, decoded, final);
  2430. }
  2431. public string decode(CodeContext/*!*/ context, [NotNull]string input, [DefaultParameterValue(false)]bool final) {
  2432. if (_decoder == null) {
  2433. return DecodeWorker(context, input, final);
  2434. }
  2435. return decode(context, new Bytes(input.MakeByteArray()), final);
  2436. }
  2437. private string DecodeWorker(CodeContext/*!*/ context, string decoded, bool final) {
  2438. if (_pendingCR && (final || decoded.Length > 0)) {
  2439. decoded = "\r" + decoded;
  2440. _pendingCR = false;
  2441. }
  2442. if (decoded.Length == 0) {
  2443. return decoded;
  2444. }
  2445. // retain last "\r" to avoid splitting "\r\n"
  2446. if (!final && decoded.Length > 0 && decoded[decoded.Length - 1] == '\r') {
  2447. decoded = decoded.Substring(0, decoded.Length - 1);
  2448. _pendingCR = true;
  2449. }
  2450. if (_translate || _seenNL != LineEnding.All) {
  2451. int crlf = decoded.count("\r\n");
  2452. int cr = decoded.count("\r") - crlf;
  2453. if (_seenNL != LineEnding.All) {
  2454. int lf = decoded.count("\n") - crlf;
  2455. _seenNL |=
  2456. (crlf > 0 ? LineEnding.CRLF : LineEnding.None) |
  2457. (lf > 0 ? LineEnding.LF : LineEnding.None) |
  2458. (cr > 0 ? LineEnding.CR : LineEnding.None);
  2459. }
  2460. if (_translate) {
  2461. if (crlf > 0) {
  2462. decoded = decoded.Replace("\r\n", "\n");
  2463. }
  2464. if (cr > 0) {
  2465. decoded = decoded.Replace('\r', '\n');
  2466. }
  2467. }
  2468. }
  2469. return decoded;
  2470. }
  2471. public PythonTuple getstate(CodeContext/*!*/ context) {
  2472. object buf = Bytes.Empty;
  2473. int flags = 0;
  2474. if (_decoder != null) {
  2475. PythonTuple state = (PythonTuple)PythonOps.Invoke(context, _decoder, "getstate");
  2476. buf = state[0];
  2477. flags = Converter.ConvertToInt32(state[1]) << 1;
  2478. }
  2479. if (_pendingCR) {
  2480. flags |= 1;
  2481. }
  2482. return PythonTuple.MakeTuple(buf, flags);
  2483. }
  2484. internal void GetState(CodeContext/*!*/ context, out Bytes buf, out int flags) {
  2485. PythonTuple state = (PythonTuple)PythonOps.Invoke(context, _decoder, "getstate");
  2486. buf = GetBytes(state[0], "getstate");
  2487. flags = Converter.ConvertToInt32(state[1]) << 1;
  2488. if (_pendingCR) {
  2489. flags |= 1;
  2490. }
  2491. }
  2492. public void setstate(CodeContext/*!*/ context, [NotNull]PythonTuple state) {
  2493. object buf = state[0];
  2494. int flags = Converter.ConvertToInt32(state[1]);
  2495. _pendingCR = (flags & 1) != 0;
  2496. if (_decoder != null) {
  2497. PythonOps.Invoke(context, _decoder, "setstate", PythonTuple.MakeTuple(buf, flags >> 1));
  2498. }
  2499. }
  2500. internal void SetState(CodeContext/*!*/ context, Bytes buffer, int flags) {
  2501. _pendingCR = (flags & 1) != 0;
  2502. if (_decoder != null) {
  2503. PythonOps.Invoke(context, _decoder, "setstate", PythonTuple.MakeTuple(buffer, flags >> 1));
  2504. }
  2505. }
  2506. public void reset(CodeContext/*!*/ context) {
  2507. _seenNL = LineEnding.None;
  2508. _pendingCR = false;
  2509. if (_decoder != null) {
  2510. PythonOps.Invoke(context, _decoder, "reset");
  2511. }
  2512. }
  2513. public object newlines {
  2514. get {
  2515. switch (_seenNL) {
  2516. case LineEnding.None:
  2517. return null;
  2518. case LineEnding.CR:
  2519. return "\r";
  2520. case LineEnding.LF:
  2521. return "\n";
  2522. case LineEnding.CRLF:
  2523. return "\r\n";
  2524. case LineEnding.CR | LineEnding.LF:
  2525. return PythonTuple.MakeTuple("\r", "\n");
  2526. case LineEnding.CR | LineEnding.CRLF:
  2527. return PythonTuple.MakeTuple("\r", "\r\n");
  2528. case LineEnding.LF | LineEnding.CRLF:
  2529. return PythonTuple.MakeTuple("\n", "\r\n");
  2530. default: // LineEnding.All
  2531. return PythonTuple.MakeTuple("\r", "\n", "\r\n");
  2532. }
  2533. }
  2534. }
  2535. }
  2536. #region BlockingIOException
  2537. [PythonType, DynamicBaseType]
  2538. private class BlockingIOError : PythonExceptions._EnvironmentError {
  2539. private int _characters_written;
  2540. public BlockingIOError(PythonType cls) : base(cls) { }
  2541. public override void __init__(params object[] args) {
  2542. switch (args.Length) {
  2543. case 2:
  2544. base.__init__(args);
  2545. break;
  2546. case 3:
  2547. _characters_written = GetInt(args[2], "an integer is required");
  2548. base.__init__(args[0], args[1]);
  2549. break;
  2550. default:
  2551. if (args.Length < 2) {
  2552. throw PythonOps.TypeError("BlockingIOError() takes at least 2 arguments ({0} given)", args.Length);
  2553. }
  2554. throw PythonOps.TypeError("BlockingIOError() takes at most 3 arguments ({0} given)", args.Length);
  2555. }
  2556. }
  2557. public int characters_written {
  2558. get { return _characters_written; }
  2559. set { _characters_written = value; }
  2560. }
  2561. }
  2562. private class _BlockingIOErrorException : IOException {
  2563. public _BlockingIOErrorException(string msg) : base(msg) { }
  2564. }
  2565. #endregion
  2566. #region Private implementation details
  2567. private static HashSet<char> _validModes = MakeSet("abrtwU+");
  2568. private static HashSet<char> MakeSet(string chars) {
  2569. HashSet<char> res = new HashSet<char>();
  2570. for (int i = 0; i < chars.Length; i++) {
  2571. res.Add(chars[i]);
  2572. }
  2573. return res;
  2574. }
  2575. private static BigInteger GetBigInt(object i, string msg) {
  2576. BigInteger res;
  2577. if (TryGetBigInt(i, out res)) {
  2578. return res;
  2579. }
  2580. throw PythonOps.TypeError(msg);
  2581. }
  2582. private static bool TryGetBigInt(object i, out BigInteger res) {
  2583. if (i is BigInteger) {
  2584. res = (BigInteger)i;
  2585. return true;
  2586. } else if (i is int) {
  2587. res =(BigInteger)(int)i;
  2588. return true;
  2589. } else if (i is long) {
  2590. res = (BigInteger)(long)i;
  2591. return true;
  2592. }
  2593. Extensible<int> ei = i as Extensible<int>;
  2594. if (ei != null) {
  2595. res = (BigInteger)ei.Value;
  2596. return true;
  2597. }
  2598. Extensible<BigInteger> ebi = i as Extensible<BigInteger>;
  2599. if (ebi != null) {
  2600. res = ebi.Value;
  2601. return true;
  2602. }
  2603. res = BigInteger.Zero;
  2604. return false;
  2605. }
  2606. private static int GetInt(object i) {
  2607. return GetInt(i, null, null);
  2608. }
  2609. private static int GetInt(object i, int defaultValue) {
  2610. return GetInt(i, defaultValue, null, null);
  2611. }
  2612. private static int GetInt(object i, string msg, params object[] args) {
  2613. int res;
  2614. if (TryGetInt(i, out res)) {
  2615. return res;
  2616. }
  2617. if (msg == null) {
  2618. throw PythonOps.TypeError("integer argument expected, got '{0}'", PythonTypeOps.GetName(i));
  2619. } else {
  2620. throw PythonOps.TypeError(msg, args);
  2621. }
  2622. }
  2623. private static int GetInt(object i, int defaultValue, string msg, params object[] args) {
  2624. if (i == null) {
  2625. return defaultValue;
  2626. }
  2627. return GetInt(i, msg, args);
  2628. }
  2629. private static bool TryGetInt(object i, out int value) {
  2630. if (i == null) {
  2631. value = int.MinValue;
  2632. return false;
  2633. } else if (i is int) {
  2634. value = (int)i;
  2635. return true;
  2636. } else if (i is BigInteger) {
  2637. return ((BigInteger)i).AsInt32(out value);
  2638. }
  2639. Extensible<int> ei = i as Extensible<int>;
  2640. if (ei != null) {
  2641. value = ei.Value;
  2642. return true;
  2643. }
  2644. Extensible<BigInteger> ebi = i as Extensible<BigInteger>;
  2645. if (ebi != null) {
  2646. return ebi.Value.AsInt32(out value);
  2647. }
  2648. value = int.MinValue;
  2649. return false;
  2650. }
  2651. /// <summary>
  2652. /// Convert string or bytes into bytes
  2653. /// </summary>
  2654. private static Bytes GetBytes(object o, string name) {
  2655. if(o == null)
  2656. return null;
  2657. Bytes bytes = o as Bytes;
  2658. if (bytes != null) {
  2659. return bytes;
  2660. }
  2661. string s = o as string;
  2662. if (s == null) {
  2663. Extensible<string> es = o as Extensible<string>;
  2664. if (es != null) {
  2665. s = es.Value;
  2666. }
  2667. }
  2668. if (s != null) {
  2669. return PythonOps.MakeBytes(s.MakeByteArray());
  2670. }
  2671. throw PythonOps.TypeError("'" + name + "' should have returned bytes");
  2672. }
  2673. /// <summary>
  2674. /// Convert most bytearray-like objects into IList of byte
  2675. /// </summary>
  2676. private static IList<byte> GetBytes(object buf) {
  2677. IList<byte> bytes;
  2678. bytes = buf as IList<byte>;
  2679. if (bytes != null) {
  2680. return bytes;
  2681. }
  2682. string str = buf as string;
  2683. if (str == null) {
  2684. if (buf is Extensible<string>) {
  2685. str = ((Extensible<string>)buf).Value;
  2686. }
  2687. }
  2688. if (str != null) {
  2689. return PythonOps.MakeByteArray(str);
  2690. }
  2691. ArrayModule.array arr = buf as ArrayModule.array;
  2692. if (arr != null) {
  2693. return arr.ToByteArray();
  2694. }
  2695. throw PythonOps.TypeError("must be bytes or buffer, not {0}", PythonTypeOps.GetName(buf));
  2696. }
  2697. #endregion
  2698. }
  2699. }