-
Notifications
You must be signed in to change notification settings - Fork 35
ICryptoolStreamUsage
Nils Kopal edited this page Feb 15, 2022
·
4 revisions
ICryptoolStream is a replacement for the now obsolete CryptoolStream class. With ICryptoolStream a plugin can pass data as byte stream to other plugins.
Features:
- Supports 0..n concurrent readers on one ICryptoolStream
- Clean separation between writer and reader -- reading plugins can't disturb the writing plugin or other reading instances
- Does not forget data -- new readers can be created at any time and support random seeking
- Uses internal byte array as underlying buffer and switches automagically to a temporary file, if data exceeds a certain size
- Supports chunked streaming -- receivers can read and process data even if the sender has not finished writing
- https://github.com/CrypToolProject/CrypTool-2/blob/main/CrypPluginBase/IO/ICryptoolStream.cs
- https://github.com/CrypToolProject/CrypTool-2/blob/main/CrypPluginBase/IO/CStreamWriter.cs
- https://github.com/CrypToolProject/CrypTool-2/blob/main/CrypPluginBase/IO/CStreamReader.cs
- Create an output property (e.g. called "OutputStream") with type ICryptoolStream.
- In Execute() create a new CStreamWriter.
- Set the CStreamWriter as OutputStream property (will be implicitly downcasted).
- Announce the OutputStream update with OnPropertyChanged("OutputStream").
- Pass data to the stream via CStreamWriter.Write().
- Call CStreamWriter.Close() when finished.
- Best practice is to not care about disposal of writer.
public class PluginA
{
public ICryptoolStream OutputStream
{
get;
private set;
}
public void Execute()
{
CStreamWriter writer = new CStreamWriter();
OutputStream = writer;
OnPropertyChanged("OutputStream");
while(condition)
{
byte[] data = GenerateData();
writer.Write(data);
}
writer.Close();
}
}
Note: It is only possible to write single bytes or byte arrays to an ICryptoolStream. This means if other data types should be written the developer has to transform them to a byte array first. If for example a string should be written it needs to be decoded frist to bytes via an encoder. The following example shows a function that could be called with a string to write the correspondent byte array to an ICryptoolStream. So every time a string should be written this function can be called.
#!cpp
//global variables
private Encoding encoding = Encoding.UTF8; // shoose an encoding; UTF-8 or UTF-16 is recommended
private CStreamWriter outputStreamWriter; // needs to be initialized before it can be used through WriteOutput()
private void WriteOutput(string str)
{
outputStreamWriter.Write(encoding.GetBytes(str));
}
- Create an input property (e.g. called "InputStream") with type ICryptoolStream.
- In Execute() call CreateReader() on that ICryptoolStream to get a new CStreamReader.
- Retrieve data with CStreamReader.Read() in a loop.
- End loop when read attempt returns 0 bytes.
- Beware of evaluating CStreamReader.Length: writer may not have finished writing to the stream, so the length may grow.
- Best practice is to not care about disposal of reader.
public class PluginB
{
public ICryptoolStream InputStream
{
get;
set;
}
public void Execute()
{
// The "using" keywords asserts that CStreamReader.Dispose() will be called
using (CStreamReader reader = InputStream.CreateReader())
{
int bytesRead;
byte[] buffer = new byte[ANY_SIZE];
while ((bytesRead = reader.Read(buffer)) > 0)
{
// Note: buffer can contain less data than buffer.Length, therefore consider bytesRead
processData(buffer, bytesRead);
}
}
}
}
- You may use CStreamReader.WaitEof() to wait until the writer has closed the stream. When the method returns, the writer has finished and CStreamReader.Length will remain constant.
- If you don't like the property of CStreamReader.Read(byte[]), that it may return less bytes than requested, you can use CStreamReader.ReadFully(byte[]). Still, when you reach the end of a closed stream it will return less bytes.
- If you're superlazy, CStreamReader.ReadFully() (without parameters) will do all the stream reading and waiting work and deliver everything as a single byte[]. However, it is terribly inefficient and you may get memory problems when processing large data amounts. Try to avoid it.