Files
CipherStream/SourceFiles/Vigenere.cpp
2019-03-07 12:50:56 -05:00

238 lines
5.9 KiB
C++

//Ciphers/SourceFiles/Vigenere.cpp
//Matthew Ellison
// Created: 04-29-18
//Modified: 03-07-19
//This file contains the implementation of the Vigenere class
#include "../Headers/Vigenere.hpp"
#include <string>
#include <vector>
#include <cctype>
/**
* @brief The current library's version number
*
*/
const std::string Vigenere::version = "1.1";
/**
* @brief Construct a new Vigenere object
*
*/
Vigenere::Vigenere(){
reset();
}
/**
* @brief Destroy the Vigenere object
*
*/
Vigenere::~Vigenere(){
}
/**
* @brief Removes all invalid characters from input and sets it to inputString
*
* @param input The string you want to encode/decode
*/
void Vigenere::setInputString(std::string input){
//Loop through every character in input. Remove all whitespace and punctuation and make sure all letters are capital and add it to inputString
for(unsigned int cnt = 0;cnt < input.size();++cnt){
char letter = input[cnt];
if(isupper(letter)){
inputString += letter;
}
else if(islower(letter)){
inputString += toupper(letter);
}
//If the letter is whitespace or punctuation do nothing
}
}
/**
* @brief Returns the string you wish to encode/decode
*
* @return The string you wish to encode/decode
*/
std::string Vigenere::getInputString() const{
return inputString;
}
/**
* @brief Returns the encoded/decoded message
*
* @return The encoded/decoded message
*/
std::string Vigenere::getOutputString() const{
return outputString;
}
/**
* @brief Removes all invalid characters from key and sets it to keyword
*
* @param key The keyword used for the cipher
*/
void Vigenere::setKeyword(std::string key){
//Loop through every letter in the key and make sure all of them are uppercase letters
for(unsigned int cnt = 0;cnt < key.size();++cnt){
char letter = key[cnt];
if(isupper(letter)){
keyword += letter;
}
else if(islower(letter)){
keyword += toupper(letter);
}
//If it is not a letter ignore it
}
//Make sure offset is empty before adding to it
offset.clear();
setOffset();
//If after all the eliminating of unusable characters the keyword is empty throw an error
if(keyword == ""){
throw emptyKeyword();
}
}
/**
* @brief Returns the keyword you are using for the cipher
*
* @return The keyword you are using for the cipher
*/
std::string Vigenere::getKeyword() const{
return keyword;
}
/**
* @brief Uses keyword to set the offsets of the letters used during encoding/decoding
*
*/
void Vigenere::setOffset(){
//Reserve the correct size to increase speed later
offset.reserve(keyword.size());
//Loop through every letter in keyword and get the offset from A
for(char letter : keyword){
offset.push_back((letter - 'A') % 26);
}
}
/**
* @brief Returns the vector that holds the offsets of the letters used during encoding/decoding
*
* @return A the vector holding offsets of the letters used during encoding/decoding
* @note Used mostly for debuging
*/
std::vector<unsigned int> Vigenere::getOffsets() const{
return offset;
}
/**
* @brief Encodes the inputString using the Vigenere cipher and saves the result in outputString
*
* @return The encoded message
*/
std::string Vigenere::encode(){
//Reserve the correct size for the output string to increase speed for longer messages
outputString.reserve(inputString.size());
//Step through every charater in the inputString and advance it the correct amount, according to offset
for(unsigned int cnt = 0;cnt < inputString.size();++cnt){
char letter = (inputString[cnt] + offset[cnt % offset.size()]); //By using % you allow it to loop without having a separate counter
//Make sure the character is still a letter, if not, wrap around
if(letter < 'A'){
letter += 26;
}
else if(letter > 'Z'){
letter -= 26;
}
outputString += letter;
}
return outputString;
}
/**
* @brief Sets all of the variables for the cipher and returns the result
*
* @param key The keyword used in the cipher
* @param input The message that you wish to encode
* @return The encoded message
*/
std::string Vigenere::encode(std::string key, std::string input){
reset();
try{
setKeyword(key);
}
//Catch the emptyKeyword error if it was thrown
catch(emptyKeyword){
std::string errorString = "After all unusable characters were stripped away the keyword given was empty";
return errorString;
}
setInputString(input);
return encode();
}
/**
* @brief Decodes the inputString using the Vigenere cipher and saves the result in outputString
*
* @return The decoded message
*/
std::string Vigenere::decode(){
//Reserve the correct size for the output string to increase speed for longer messages
outputString.reserve(inputString.size());
//Step through every charater in the inputString and reduce it the correct amount, according to offset
for(unsigned int cnt = 0;cnt < inputString.size();++cnt){
char letter = (inputString[cnt] - offset[cnt % offset.size()]); //By using % you allow it to loop without having a separate counter
if(letter < 'A'){
letter += 26;
}
else if(letter > 'Z'){
letter -= 26;
}
outputString += letter;
}
return outputString;
}
/**
* @brief Sets all of the variables for the cipher and returns the result
*
* @param key The keyword used in the cipher
* @param input The message that you wish to decode
* @return The decoded message
*/
std::string Vigenere::decode(std::string key, std::string input){
reset();
try{
setKeyword(key);
}
//Catch the emptyKeyword error if it was thrown
catch(emptyKeyword){
std::string errorString = "After all unusable characters were stripped away the keyword given was empty";
return errorString;
}
setInputString(input);
return decode();
}
/**
* @brief Makes sure all of the variables are empty
*
*/
void Vigenere::reset(){
inputString = outputString = keyword = "";
offset.clear();
}
/**
* @brief Returns a string containing the version information
*
* @return The version information
*/
std::string Vigenere::getVersion(){
return version;
}