Problem 3
Using the Vigenere scrambler data type, we can define an object adapter that provides us with an input file stream for Vigenère ciphers. That is, this object adapter performs encoding and decoding on-the-fly while reading the contents of a file.
Assume the implementation of class Vigenere is correct. Using Vigenere, define class
iVigenereStream that satisfies the suggested specification as shown below:
#pragma once
#include <fstream>
#include <functional>
#include "Vigenere.h"
using Cipher = std::function<char ( Vigenere& aCipherProvider, char aCharacter )>;
class iVigenereStream
{
private:
std::ifstream fIStream; Vigenere fCipherProvider; Cipher fCipher;
public:
iVigenereStream( Cipher aCipher,
const std::string& aKeyword,
const char* aFileName = nullptr ); // [8]
~iVigenereStream(); // [2]
void open( const char* aFileName ); // [8]
void close(); // [2]
void reset(); // [10]
// conversion operator to bool
operator bool() { return !eof(); }
// stream positioning
uint64_t position() { return fIStream.tellg(); }
void seekstart() { fIStream.clear(); fIStream.seekg( 0, std::ios_base::beg ); }
bool good() const; // [3]
bool is_open() const; // [3]
bool eof() const; // [3]
iVigenereStream& operator>>( char& aCharacter ); // [17]
};
Class iVigenereStream is an object adapter for character file input streams. There is, however, one important characteristic of iVigenereStream that must be considered. Unlike standard character input file streams that ignore white space characters when performing formatted input by default, iVigenereStream must not skip white space characters. Hence, the underlying file stream must be processed in binary mode. In addition, we must access the characters of the underlying input file stream using ifstream’s get() method. This guarantees raw data access, which is required for the proper functioning of class iVigenereStream.
Class iVigenereStream does not define a default constructor. We always have to specify at least the scrambling mode aCipher and the keyword string aKeyword. The parameter aCipher expects a callable object. In this problem, we wish to decode a text input stream. Hence, we use the following lambda expression as parameter aCipher:
auto lCallable = []( Vigenere& aCipherProvider, char aCharacter )
{
return aCipherProvider.decode( aCharacter );
};
The lambda expression lCallable takes two arguments: a cipher provider and a character. It returns a decoded character as result.
The second argument to the constructor of iVigenereStream is aKeyword that we use to initialize the fCipherProvider member variable. (The cipher provider is a Vigenere object.)
The third constructor argument is a file name. If it is not nullptr, then the underlying fine stream must be opened.
File streams are value-based objects in C++. When these objects go out of scope, the corresponding destructor guarantees that the underlying file stream is properly closed.
The methods open() and close() have the expected semantics.
The method reset() has to restart an iVigenereStream stream. That is, this method resets the underlying cipher provider and positions the file pointer to the first character in the underlying file input stream. You can use the method seekstart() for this purpose.
The methods good(), is_open(), and eof() return the corresponding Boolean values from the underlying input file stream.
There is also a bool() method. This is a type conversion method that allows objects of type iVigenereStream to be used in a context where a Boolean value is expected. We use bool() to check if the underlying file input stream has reached end-of-file.
Finally, iVigenereStream provides formatted input for characters. This formatted input has to get a character from the underlying file input stream (note, raw input here). If we have not yet reached end-of-file, then the character must be processed by the cipher provider. That is, we call fCipher with the right arguments to obtain the result aCharacter.
You can test your implementation of iVigenereStream using the following test driver (enable #define P3 in main.cpp):
#include "iVigenereStream.h"
int runP3( string argv[2] )
{
iVigenereStream lInput( []( Vigenere& aCipherProvider, char aCharacter )
{
return aCipherProvider.decode( aCharacter );
} , argv[0], argv[1].c_str() );
if ( !lInput.good() )
{
cerr << "Cannot open input file: " << argv[1] << endl;
return 2;
}
cout << "Decoding \"" << argv[1] << "\" using \"" << argv[0] << "\"." << endl;
char lCharacter;
while ( lInput >> lCharacter )
{
cout << lCharacter;
}
lInput.close();
cout << "Completed." << endl;
return 0;
}
Running the test driver should produce the following output (Shakespeare’s Richard III). The file sample_3.txt must be in the “Working Directory”.
Decoding "sample_3.txt" using "Relations".
ACT I SCENE I
London. A Street.
Enter Gloucester.
Gloucester. Now is the winter of our discontent Made glorious summer by this sun of York;
And all the clouds that lour'd upon our house In the deep bosom of the ocean buried.
Now are our brows bound with victorious wreaths; Our bruised arms hung up for monuments;
Our stern alarums changed to merry meetings; Our dreadful marches to delightful measures.
Grim-visag'd war hath smooth'd his wrinkled front; And now, - instead of mounting barbed steeds,
To fright the souls of fearful adversaries, - He capers nimbly in a lady's chamber
To the lascivious pleasing of a lute.
But I, that am not shap'd for sportive tricks, Nor made to court an amorous looking-glass;
I, that am rudely stamp'd, and want love's majesty To strut before a wanton ambling nymph;
I, that am curtail'd of this fair proportion, Cheated of feature by dissembling nature, Deform'd, unfinish'd, sent before my time
Into this breathing world, scarce half made up, And that so lamely and unfashionable
That dogs bark at me, as I halt by them; Why, I, in this weak piping time of peace, Have no delight to pass away the time, Unless to see my shadow in the sun
And descant on mine own deformity:
And therefore, since I cannot prove a lover, To entertain these fair well-spoken days,
I am determined to prove a villain,
And hate the idle pleasures of these days. Plots have I laid, inductions dangerous, By drunken prophecies, libels, and dreams, To set my brother Clarence and the king
In deadly hate the one against the other: And if King Edward be as true and just
As I am subtle, false, and treacherous,
This day should Clarence closely be mew'd up, About a prophecy, which says, that G
Of Edward's heirs the murderer shall be.
Dive, thoughts, down to my soul: here Clarence comes.
Brother, good day: what means this armed guard That waits upon your Grace?
Completed.
Students succeed in their courses by connecting and communicating with an expert until they receive help on their questions
Consult our trusted tutors.