aspclassic-core/AspClassic.Scripting/Runtime/SharedIO.cs
Jelle Luteijn 484dbfc9d9 progress
2022-05-15 11:19:49 +02:00

307 lines
5 KiB
C#

using System;
using System.IO;
using System.Text;
using System.Threading;
using AspClassic.Scripting.Utils;
namespace AspClassic.Scripting.Runtime;
public sealed class SharedIO
{
private sealed class StreamProxy : Stream
{
private readonly ConsoleStreamType _type;
private readonly SharedIO _io;
public override bool CanRead => _type == ConsoleStreamType.Input;
public override bool CanSeek => false;
public override bool CanWrite => !CanRead;
public override long Length
{
get
{
throw new NotSupportedException();
}
}
public override long Position
{
get
{
throw new NotSupportedException();
}
set
{
throw new NotSupportedException();
}
}
public StreamProxy(SharedIO io, ConsoleStreamType type)
{
_io = io;
_type = type;
}
public override void Flush()
{
_io.GetStream(_type).Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
return _io.GetStream(_type).Read(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count)
{
_io.GetStream(_type).Write(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
}
private readonly object _mutex = new object();
private Stream _inputStream;
private Stream _outputStream;
private Stream _errorStream;
private TextReader _inputReader;
private TextWriter _outputWriter;
private TextWriter _errorWriter;
private Encoding _inputEncoding;
public Stream InputStream
{
get
{
InitializeInput();
return _inputStream;
}
}
public Stream OutputStream
{
get
{
InitializeOutput();
return _outputStream;
}
}
public Stream ErrorStream
{
get
{
InitializeErrorOutput();
return _errorStream;
}
}
public TextReader InputReader
{
get
{
InitializeInput();
return _inputReader;
}
}
public TextWriter OutputWriter
{
get
{
InitializeOutput();
return _outputWriter;
}
}
public TextWriter ErrorWriter
{
get
{
InitializeErrorOutput();
return _errorWriter;
}
}
public Encoding InputEncoding
{
get
{
InitializeInput();
return _inputEncoding;
}
}
public Encoding OutputEncoding
{
get
{
InitializeOutput();
return _outputWriter.Encoding;
}
}
public Encoding ErrorEncoding
{
get
{
InitializeErrorOutput();
return _errorWriter.Encoding;
}
}
internal SharedIO()
{
}
private void InitializeInput()
{
if (_inputStream != null)
{
return;
}
lock (_mutex)
{
if (_inputStream == null)
{
_inputStream = ConsoleInputStream.Instance;
_inputEncoding = Console.InputEncoding;
_inputReader = Console.In;
}
}
}
private void InitializeOutput()
{
if (_outputStream != null)
{
return;
}
lock (_mutex)
{
if (_outputStream == null)
{
_outputStream = Console.OpenStandardOutput();
_outputWriter = Console.Out;
}
}
}
private void InitializeErrorOutput()
{
if (_errorStream == null)
{
Stream value = Console.OpenStandardError();
Interlocked.CompareExchange(ref _errorStream, value, null);
Interlocked.CompareExchange(ref _errorWriter, Console.Error, null);
}
}
public void SetOutput(Stream stream, TextWriter writer)
{
lock (_mutex)
{
_outputStream = stream;
_outputWriter = writer;
}
}
public void SetErrorOutput(Stream stream, TextWriter writer)
{
lock (_mutex)
{
_errorStream = stream;
_errorWriter = writer;
}
}
public void SetInput(Stream stream, TextReader reader, Encoding encoding)
{
lock (_mutex)
{
_inputStream = stream;
_inputReader = reader;
_inputEncoding = encoding;
}
}
public void RedirectToConsole()
{
lock (_mutex)
{
_inputEncoding = null;
_inputStream = null;
_outputStream = null;
_errorStream = null;
_inputReader = null;
_outputWriter = null;
_errorWriter = null;
}
}
public Stream GetStream(ConsoleStreamType type)
{
return type switch
{
ConsoleStreamType.Input => InputStream,
ConsoleStreamType.Output => OutputStream,
ConsoleStreamType.ErrorOutput => ErrorStream,
_ => throw Error.InvalidStreamType(type),
};
}
public TextWriter GetWriter(ConsoleStreamType type)
{
return type switch
{
ConsoleStreamType.Output => OutputWriter,
ConsoleStreamType.ErrorOutput => ErrorWriter,
_ => throw Error.InvalidStreamType(type),
};
}
public Encoding GetEncoding(ConsoleStreamType type)
{
return type switch
{
ConsoleStreamType.Input => InputEncoding,
ConsoleStreamType.Output => OutputEncoding,
ConsoleStreamType.ErrorOutput => ErrorEncoding,
_ => throw Error.InvalidStreamType(type),
};
}
public TextReader GetReader(out Encoding encoding)
{
lock (_mutex)
{
TextReader inputReader = InputReader;
encoding = InputEncoding;
return inputReader;
}
}
public Stream GetStreamProxy(ConsoleStreamType type)
{
return new StreamProxy(this, type);
}
}