pascalabcnet/CompilerTools/EventedStreamReaderList.cs

238 lines
8.2 KiB
C#
Raw Normal View History

// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt)
2015-06-01 22:15:17 +03:00
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
2015-05-14 22:35:07 +03:00
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Timers;
namespace PascalABCCompiler
{
public class EventedStreamReaderList
{
Dictionary<StreamReader, string> StreamReaders = new Dictionary<StreamReader, string>();
Dictionary<StreamReader, string> Buffers = new Dictionary<StreamReader, string>();
Dictionary<string, Encoding> StreamEncodings = new Dictionary<string, Encoding>();
StringRecivedDelegate StringRecived;
string dataSeparator = null;
public string DataSeparator
{
get
{
return dataSeparator;
}
set
{
dataSeparator = value;
}
}
class StreamReaderObject
{
public const int BUFFER_SIZE = 1024;
public byte[] buffer = new byte[BUFFER_SIZE];
public string Ident;
public int byteoffset = 0;
public StreamReader StreamReader;
public StreamReaderObject(string Ident, StreamReader StreamReader)
{
this.Ident = Ident;
this.StreamReader = StreamReader;
}
}
public delegate void StringRecivedDelegate(string Id, string Data);
public EventedStreamReaderList(StringRecivedDelegate StringRecived)
{
this.StringRecived = StringRecived;
}
private void Read_Callback1(IAsyncResult ar)
{
if (ar == null)
return;
StreamReaderObject so = (StreamReaderObject)ar.AsyncState;
if (!StreamReaders.ContainsKey(so.StreamReader))
return;
Stream s = so.StreamReader.BaseStream;
string buffer = Buffers[so.StreamReader];
try
{
int read = s.EndRead(ar);
if (read > 0)
{
string str = StreamEncodings[so.Ident].GetString(so.buffer, 0, read);
if (dataSeparator != null)
{
buffer += str;
int i;
do
{
i = buffer.IndexOf(dataSeparator);
if (i > 0)
{
StringRecived(so.Ident, buffer.Substring(0, i));
buffer = buffer.Remove(0, i + dataSeparator.Length);
}
} while (i > 0);
}
else
StringRecived(so.Ident, str);
Buffers[so.StreamReader] = buffer;
s.BeginRead(so.buffer, 0, StreamReaderObject.BUFFER_SIZE, Read_Callback, so);
}
}
catch
{
Remove(so.Ident);
}
}
private void Read_Callback(IAsyncResult ar)
{
if (ar == null)
return;
StreamReaderObject so = (StreamReaderObject)ar.AsyncState;
if (!StreamReaders.ContainsKey(so.StreamReader))
return;
Stream s = so.StreamReader.BaseStream;
string buffer = Buffers[so.StreamReader];
try
{
int read = s.EndRead(ar);
// Новое поле byteoffset говорит о том, что с прошлого раза мы учли дополнительный байт
2015-05-14 22:35:07 +03:00
read += so.byteoffset;
if (read > 0)
{
Encoding en = StreamEncodings[so.Ident];
Decoder d = en.GetDecoder();
char []cc = new char[read];
int bytesUsed;
int charsUsed;
bool completed;
d.Convert(so.buffer, 0, read, cc, 0, read, false, out bytesUsed, out charsUsed, out completed);
string newstr = new string(cc, 0, charsUsed);
string str = en.GetString(so.buffer, 0, read);
// К сожалению, ошибочный байт устанавливается за счет разницы длин str и newstr
// Надо бы оптимизировать
2015-05-14 22:35:07 +03:00
byte prevbyte = 0;
if (str.Length != newstr.Length)
prevbyte = so.buffer[bytesUsed - 1];
if (dataSeparator != null)
{
buffer += newstr;
int i;
do
{
i = buffer.IndexOf(dataSeparator);
if (i > 0)
{
StringRecived(so.Ident, buffer.Substring(0, i));
buffer = buffer.Remove(0, i + dataSeparator.Length);
}
} while (i > 0);
}
else
StringRecived(so.Ident, newstr);
Buffers[so.StreamReader] = buffer;
if (prevbyte == 0)
{
so.byteoffset = 0;
s.BeginRead(so.buffer, 0, StreamReaderObject.BUFFER_SIZE, Read_Callback, so);
}
else
{
so.byteoffset = 1;
so.buffer[0] = prevbyte;
s.BeginRead(so.buffer, 1, StreamReaderObject.BUFFER_SIZE - 1, Read_Callback, so);
}
}
}
catch (Exception ex)
2015-05-14 22:35:07 +03:00
{
Remove(so.Ident);
}
}
StreamReader getReader(string id)
{
foreach (StreamReader sr in StreamReaders.Keys)
if (StreamReaders[sr] == id)
return sr;
return null;
}
/*public string ReadString(string id, int size_in_bytes)
{
StreamReader sr = getReader(id);
Stream s = sr.BaseStream;
s.EndRead(null);
byte[] buffer = new byte[size_in_bytes];
s.Read(buffer, 0, size_in_bytes);
string str = StreamEncodings[id].GetString(buffer, 0, size_in_bytes);
StreamReaderObject o = new StreamReaderObject(id, sr);
sr.BaseStream.BeginRead(o.buffer, 0, StreamReaderObject.BUFFER_SIZE, Read_Callback, o);
return str;
}*/
public int RB(StreamReader sr, char[] cc, int from, int count)
{
//sr.ReadLine();
return 0;
}
public void Add(StreamReader sr, string id, Encoding Encoding)
{
StreamReaders.Add(sr, id);
Buffers.Add(sr, "");
if(StreamEncodings.ContainsKey(id))
StreamEncodings[id] = Encoding;
else
StreamEncodings.Add(id, Encoding);
StreamReaderObject o = new StreamReaderObject(id, sr);
sr.BaseStream.BeginRead(o.buffer, 0, StreamReaderObject.BUFFER_SIZE, Read_Callback, o);
}
public void SetEncoding(string id, Encoding Encoding)
{
StreamEncodings[id] = Encoding;
}
public Encoding GetEncoding(string id)
{
return StreamEncodings[id];
}
public void RemoveAll()
{
StreamReaders.Clear();
Buffers.Clear();
}
public void Remove(string id)
{
StreamEncodings.Remove(id);
List<StreamReader> to_delete = new List<StreamReader>();
foreach (StreamReader sr in StreamReaders.Keys)
if (StreamReaders[sr] == id)
to_delete.Add(sr);
foreach (StreamReader sr in to_delete)
{
Buffers.Remove(sr);
StreamReaders.Remove(sr);
}
}
}
}