2

I am trying to decorate the Stream class with a CaesarStream class, which basically applies Caesar cipher to both Read and Write operations. I've managed to override the Write method quite easily, but the Read is giving me a headache. From what I understand, I need to call the underlying FileStream's Read method and somehow modify it, but how do I make it read the values while also adding a number to each byte, similar to what I did in the Write() method? This is harder for me, because Read's return value is just the amount of bytes read, not the actual read items.

public class CaesarStream : Stream
{
    private int _offset;
    private FileStream _stream;

    public CaesarStream(FileStream stream, int offset)
    {
        _offset = offset;
        _stream = stream;
    }
    public override int Read(byte[] array, int offset, int count)
    {
        //I imagine i need to call 
        //_stream.Read(array, offset, count);
        //and modify the array, but how do i make my stream return it afterwards?
        //I have no access to the underlying private FileStream fields so I'm clueless
    }
    public override void Write(byte[] buffer, int offset, int count)
    {
        byte[] changedBytes = new byte[buffer.Length];

        int index = 0;
        foreach (byte b in buffer)
        {
            changedBytes[index] = (byte) (b + (byte) _offset);
            index++;
        }

        _stream.Write(changedBytes, offset, count);
    }
}

PS I know i should also check the amount of bytes read/written and keep reading/writing until it's finished, but I haven't gotten to that yet. I'd like to be done with the reading part first.

Marcin
  • 380
  • 3
  • 20
  • 1
    You just modify the `array` in the same(only by detracting the `_offset`) way you do it in the `Write` method. You don't need to return anything else then the return value of `base.Read`, because `array` is a reference - http://stackoverflow.com/questions/967402/are-arrays-or-lists-passed-by-default-by-reference-in-c. – Eugene Podskal Apr 16 '16 at 20:14
  • @Eugene Just to make sure I understand you correctly, I call the FileStream's Read and pass to it an array of shifted zeros, and it will read into it? – Marcin Apr 16 '16 at 20:18
  • 1
    @Marchin You call `base.Read` with the arguments you receive, then you iterate over each element in the array (up to the returned by `base.Read` count) and decipher them in place. The caller will then have the already deciphered data in the `array` it passed to you. – Eugene Podskal Apr 16 '16 at 20:20
  • That worked, thank you very much. It was actually simpler than I expected – Marcin Apr 16 '16 at 20:27

1 Answers1

2

Following Eugene's advice I managed to make it work as intended, here's the code in case someone would like to see it:

public class CaesarStream : Stream
{
    private int _offset;
    private FileStream _stream;


    public CaesarStream(FileStream stream, int offset)
    {
        _offset = offset;
        _stream = stream;
    }

    public override int Read(byte[] array, int offset, int count)
    {
        int retValue = _stream.Read(array, offset, count);

        for (int a = 0; a < array.Length; a++)
        {
            array[a] = (byte) (array[a] - (byte) _offset);
        }

        return retValue;
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        byte[] changedBytes = new byte[buffer.Length];

        int index = 0;
        foreach (byte b in buffer)
        {
            changedBytes[index] = (byte) (b + (byte) _offset);
            index++;
        }

        _stream.Write(changedBytes, offset, count);
    }
}
Marcin
  • 380
  • 3
  • 20
  • These methods should take offset and count into account. As they stand they modify the entire array. – usr Apr 16 '16 at 22:40