Skip to content

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
See class documentation for more information:

Table of Contents

How to use CStreamWriter

  • 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));
}

How to use CStreamReader

  • 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);
			}
		}
	}
}

Hints for implementing lazy readers

  • 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.

See also

Clone this wiki locally