C++ Caesar Cipher
// Start with the inclusion of libraries
#include <iostream> //The library of io functions
#include <fstream> //The library of external stream functions
#include <cstdlib> //The library for external errors
#include <string> //The library for string functions
#include <cmath> //The library of C math functions
#include <iomanip> //Allows setting widths, etc. for I/O
#include <stdlib.h>
#include <stdio.h>
#include<vector>
using namespace std;
// Define all of the prototypes for functions used in the program
// Counts the number of unique letters seen
int countunique(int *array, int size);
// Creates the input file and formats it for use by the cipher section.
void createinput(string ifile, string ofile);
// Creates the encoded input file
void createcipher(int key, string ifile, string ofile);
// Finds and counts the number of digrams
int digram(int *pointer, string ifile);
// Counts the letter frequency in the encoded input file
int lettercount(int*, string ifile, string ofile);
// Finds the highest count in the singlton (or any other) array
int singleton(int*, int size);
// Trims an input file to the right size starting at an offset
void trimfile(string ifile, string ofile, int offset, int size);
// Begin the main function for testing
int main(int argc, char* argv[])
{
int count = 0;
int second = 0;
int singlefreq[26];
int *single = singlefreq;
int delta;
int loop; //The loop counter for arguments
int final = 0;
int totalcnt;
int key = -1; //Sets the key value
int len = 0; //The length to investigate for testing
int off; //Holds the offset into the file
double m; //Holds the metric error value
char loopletter;
float percent;
string ifile1 = "";
string ofile1 = "";
string deflt = "c:\\dissertation\\ShiftandSubcipherC++files\\clean.txt";
string ifile2 = "";
string ofile2 = ""; //Holds selected file path names
string cmdarg; //Holds the command line argument
string stop = "l"; //Gives the stop condition, assumes l
string reportfile = "c:\\dissertation\\test\\report.txt";
ofstream outs; //Declare an output stream for reporting
int digramc[676]; //Set up the digram array
int *two = digramc; //Point to the digram array
int dicount = 0; //Holds the count of the number of digrams
int total = 0; //Counts the total number of letters seen for analysis
for (loop = 1; loop<argc; loop++) //Decide if we have arguments or must use defaults
{
if (!argv[1])
{
// cout << "No argument found.\n";
ifile1 = deflt;
}
else
{
cmdarg = argv[loop];
if (cmdarg == "-k")
{
loop++;
key = atoi(argv[loop]);
cout << "key = " << key << endl;
}
if (cmdarg == "-l")
{
loop++;
len = atoi(argv[loop]);
cout << "Run for " << len << " characters.\n";
}
if (cmdarg == "-m")
{
loop++;
m = atof(argv[loop]);
cout << "Run until and error of " << m << "\n";
}
if (cmdarg == "-off")
{
loop++;
off = atoi(argv[loop]);
cout << "Start the analysis " << off << " characters into the file.\n";
}
if (cmdarg == "-stop")
{
loop++;
stop = argv[loop];
cout << "Stop for " << stop << "\n";
}
if (cmdarg == "-i")
{
loop++;
ifile2 = argv[loop];
cout << "Using input file " << ifile2 << "\n";
}
if (cmdarg == "-o")
{
loop++;
ofile2 = argv[loop];
cout << "Using outpuf file " << ofile2 << endl;
}
}
}
for (count = 0; count<26; count++) //Initialize the frequency arrays to no count
{
singlefreq[count] = 0;
}
for (count = 0; count<676; count++) //Initialize the digram array to no count
{
digramc[count] = 0;
}
createinput(ifile2, ofile2);
createcipher(key, ofile2, ofile2);
// cout << ofile2 << endl;
trimfile(ofile2, ofile2, off, len);
totalcnt = lettercount(single, ofile2, ofile2);
cout << "\n\n";
/* for(count=0;count<26;count++)
{
loopletter = 97 + count;
percent = (singlefreq[count]*100/totalcnt);
cout << "For the letter " << loopletter << ", the count = " << setw(10) << setfill('-') << singlefreq[count]
<< " " << setw(4) << percent << "%" << endl;
total = total + singlefreq[count];
}*/
cout << "Total number of letters analyzed " << setw(10) << setfill('-') << total << endl;
delta = singleton(single, 26);
final = delta;
delta = delta + 97;
cout << endl << endl << "The letter E is most likely offset to " << char(delta) << endl;
if (final < 5)
{
final = final + 22;
}
else{
final = final - 4;
}
cout << "This corresponds to a shift of " << final << "\n\n\n";
m = float(abs(final - key)) / float(countunique(single, 26));
// cout << m << "=" << float(abs(final-key)) << "/" << float(countunique(single,26))<< endl;
dicount = digram(two, ofile2);
outs.open(reportfile.c_str(), ios::app); // Open the output stream as a binary input stream
if (outs.fail()) // If the input stream cannot open, report it then close the program
{
cerr << "\n\n ERROR - Cannot open " << reportfile << " for reading.\n";
// return EXIT_FAILURE; //failure return
}
else {
std::cout << "\nOpened the file " << reportfile << ".\n";
}
outs << ifile2 << "," << key << "," << final << "," << len << "," << off << "," << m << endl;
outs.close();
return 0;
}
void createinput(string ifile, string ofile)
{
char ch;
int val = 1;
int count = 0;
// Give the default location of the file containing the data to be read in
string table = "c:\\dissertation\\data.txt"; // Set up a default file for input
string tablein;
string outfile = "c:\\dissertation\\out.txt"; // Set up a default file for output
ifstream ins; // Declare ins an input stream
ofstream outs; // Declare outs and output stream
// cout << "In createinput\n";
if (ifile != "")
{
// cout << "Forming the filename with exenteder\n";
tablein = ifile + ".txt";
// cout << "Creating clean file from " << tablein << endl;
}
else
{
tablein = "i";
}
if (tablein != "i")
{
table = tablein;
}
ins.open(table.c_str(), ios::binary); // Open the input stream as a binary input stream
if (ins.fail()) // If the input stream cannot open, report it then close the program
{
cerr << "\n\n ERROR - Cannot open " << table << " for reading.\n";
// return EXIT_FAILURE; //failure return
}
else {
std::cout << "\nOpened the file " << table << ".\n";
}
// cout << "Have ofile as " << ofile << endl;
if (ofile != "")
{
outfile = ofile + "\\out.txt";
cout << "Creating outfile as " << outfile << endl;
}
outs.open(outfile.c_str(), ios::binary); // Open the output stream as a binary input stream
if (outs.fail()) // If the input stream cannot open, report it then close the program
{
cerr << "\n\n ERROR - Cannot open " << outfile << " for reading.\n";
// return EXIT_FAILURE; //failure return
}
else {
std::cout << "\nOpened the file " << outfile << ".\n";
}
ins >> ch;
// cout << ch; //<< "\n";
while (!ins.eof()){
if (((ch >= 65) && (ch < 91)) || ((ch >= 97) && (ch < 123))) //Check if this is an alpha character
{
if ((ch >= 65) && (ch < 91))
{
ch = ch + 32;
}
// std::cout << ch; // << "\n";
outs << ch;
count++;
}
// std::cout << count << "\n";
ins >> ch;
};
std::cout << "\n\nFinal charater count = " << count << "\n\n\n";
ins.close(); // Close the input stream
// cout << "\nClosed input file " << table << ".\n";
outs.close(); // Close the output file stream
// cout << "\nClosed output file " << outfile << ".\n\n\n";
}
void createcipher(int key, string ifile, string ofile)
{
unsigned char ch;
int offset;
int val = 0;
cout << "Read in a key value of: " << key << endl;
// Give the default location of the file containing the data to be read in
string table = "c:\\dissertation\\out.txt"; // Set up a default file for input
string tablein;
string outfile = "c:\\dissertation\\cipher.txt"; // Set up a default file for output
string keys;
ifstream ins; // Declare ins an input stream
ofstream outs; // Declare outs and output stream
// cout << "In createcipher\n";
if (ifile != "")
{
tablein = ifile + "\\out.txt";
}
else
{
tablein = "i";
}
if (tablein != "i")
{
table = tablein;
}
ins.open(table.c_str(), ios::binary); // Open the input stream as a binary input stream
if (ins.fail()) // If the input stream cannot open, report it then close the program
{
cerr << "\n\n ERROR - Cannot open " << table << " for reading.\n";
// return EXIT_FAILURE; //failure return
}
else {
std::cout << "\nOpened the file " << table << ".\n";
}
if (ofile != "")
{
outfile = ofile + "\\cipher" + ".txt";
}
outs.open(outfile.c_str(), ios::binary); // Open the output stream as binary input stream
if (outs.fail()) // If the input stream cannot open, report it then close the program
{
cerr << "\n\n ERROR - Cannot open " << outfile << " for reading.\n";
// return EXIT_FAILURE; //failure return
}
else {
std::cout << "\nOpened the file " << outfile << ".\n";
}
if (key == -1)
{
while (val == 0)
{
cout << "\n\nPlease input the shift for the cipher (from 1 to 25): ";
cin >> offset;
if ((offset >= 1) && (offset < 26))
{
cout << "\n\nYou have entered an offset of " << offset << ".\n\n\n";
val = 1;
}
else
{
cout << "You have entered an invalid number, you will be prompted again for the right input value.\n";
}
};
}
else
{
offset = key;
}
ins >> ch;
ch = ch + offset;
// cout << ch; //<< "\n";
while (!ins.eof()){
if (ch > 'z') //Check if this is an alpha character
{
ch = ch - 26;
// cout << ch;
}
// std::cout << ch << " " << int(ch) << " " << offset <<" " << ch+offset <<" ;"; // << "\n";
outs << ch;
ins >> ch;
ch = ch + offset;
};
ins.close(); // Close the input stream
// cout << "\n\nClosed input file " << table << ".\n";
outs.close(); // Close the output file stream
// cout << "\nClosed output file " << outfile << ".\n\n\n";
}
int lettercount(int *pointer, string ifile, string ofile)
{
int lettercount = 0;
int offset;
char target;
// Give the default location of the file containing the data to be read in
string table = "c:\\dissertation\\cipher.txt"; // Set up a default file for input
string tablein;
// string outfile = "c:\\dissertation\\cipher.txt"; // Set up a default file for output
ifstream ins; // Declare ins an input stream
// ofstream outs; // Declare outs and output stream
// cout << "In lettercount\n";
if (ifile != "")
{
tablein = ifile + "\\newcipher.txt";
}
else
{
tablein = "i";
}
if (tablein != "i")
{
table = tablein;
}
// cout << "Counting from the file " << table << endl;
ins.open(table.c_str(), ios::binary); // Open the input stream as a binary input stream
if (ins.fail()) // If the input stream cannot open, report it then close the program
{
cerr << "\n\n ERROR - Cannot open " << table << " for reading.\n";
// return EXIT_FAILURE; //failure return
}
else {
std::cout << "\n\nOpened the file " << table << ".\n";
}
ins >> target;
while (!ins.eof())
{
// cout << target << "\n";
lettercount = lettercount + 1;
offset = target - 97;
// cout << offset << endl;
pointer[offset]++;
// cout << pointer[offset] << endl;
ins >> target;
};
cout << "Total " << setw(7) << setfill('-') << lettercount << endl;
ins.close();
// cout << lettercount << endl;
return lettercount;
}
int singleton(int *letter, int size)
{
int loop = 0;
int highest = 0; //Holds the highest letter count to date in the loop
int tempval = 0; //Holds the present value for the letter count
int offset = 0; //Holds the letter offset for the highest value
for (loop = 0; loop<size; loop++)
{
tempval = letter[loop];
if (tempval > highest)
{
highest = tempval;
offset = loop;
}
}
return offset;
}
int digram(int *pointer, string ifile)
{
int lettercount = 0;
int offset1, offset2;
int index;
int let1offset, let2offset;
char target;
char target2;
// Give the default location of the file containing the data to be read in
string table = "c:\\dissertation\\cipher.txt"; // Set up a default file for input
string tablein;
// string outfile = "c:\\dissertation\\cipher.txt"; // Set up a default file for output
ifstream ins; // Declare ins an input stream
// ofstream outs; // Declare outs and output stream
// cout << "In digram\n";
if (ifile != "")
{
tablein = ifile + "\\cipher.txt";
}
else
{
tablein = "i";
}
if (tablein != "i")
{
table = tablein;
}
ins.open(table.c_str(), ios::binary); // Open the input stream as a binary input stream
if (ins.fail()) // If the input stream cannot open, report it then close the program
{
cerr << "\n\n ERROR - Cannot open " << table << " for reading.\n";
// return EXIT_FAILURE; //failure return
}
else {
std::cout << "\n\nOpened the file " << table << ".\n";
}
ins >> target;
ins >> target2;
cout << target << target2;
while (!ins.eof())
{
// cout << target << "\n";
lettercount = lettercount + 1;
// offset = target - 97;
// cout << offset << endl;
// pointer[offset]++;
// cout << pointer[offset] << endl;
target = target2;
ins >> target2;
offset1 = target - 97;
offset2 = target2 - 97;
index = (offset1 * 26) + offset2;
// cout << target << target2 << endl;
// cout << offset1 << " " << offset2 << " " << index << endl;
pointer[index]++;
};
ins.close();
// cout << lettercount << endl;
/* for(offset1=0;offset1<677;offset1++)
{
target2 = (offset1 % 26) + 97;
target = ((offset1 - target2 - 97)/26) + 97;
cout << "Number of " << target << target2 << " = " << pointer[offset1] << endl;
}
*/
cout << "\n\n";
offset2 = singleton(pointer, 676);
cout << offset2 << endl << endl;
let2offset = (offset2 % 26);
let1offset = ((offset2 - let2offset)) / 26;
if (let1offset < 19)
{
let1offset = let1offset + 7;
}
else
{
let1offset = let1offset - 19;
}
if (let2offset < 8)
{
let2offset = let2offset + 19;
}
else
{
let2offset = let2offset - 7;
}
cout << "Calculated the first digram letter offset to be " << let1offset << endl;
cout << "Calculated the second digram letter offset to be " << let2offset << endl << endl;
return lettercount;
}
int countunique(int *array, int size)
{
int cnt = 0; //Number of unique letters seen
int loop; //Loop counter
for (loop = 0; loop<size; loop++)
{
if (array[loop]>0)
{
cnt++;
}
}
return cnt;
}
void trimfile(string ifile, string ofile, int offset, int size)
{
int loop, cnt; //Loop counters
char letter; //Holds the letter from the input file
string cutfile; //The file to cut
string finalfile; //The final cut from the file
ifstream ins; //Declare the input stream
ofstream outs; //Declare an output stream
// cout << "In trimfile\n";
cutfile = ifile + "\\cipher.txt";
finalfile = ofile + "\\newcipher.txt";
// cout << ifile << " " << ofile << endl << endl;
// cout << cutfile << " " << finalfile << endl;
ins.open(cutfile.c_str(), ios::binary); // Open the input stream as a binary input stream
if (ins.fail()) // If the input stream cannot open, report it then close the program
{
cerr << "\n\n ERROR - Cannot open " << cutfile << " for reading.\n";
// return EXIT_FAILURE; //failure return
}
else {
std::cout << "\n\nOpened the file " << cutfile << ".\n";
}
outs.open(finalfile.c_str(), ios::binary); // Open the output stream as a binary input stream
if (outs.fail()) // If the input stream cannot open, report it then close the program
{
cerr << "\n\n ERROR - Cannot open " << finalfile << " for reading.\n";
// return EXIT_FAILURE; //failure return
}
else {
std::cout << "\nOpened the file " << finalfile << ".\n";
}
for (cnt = 0; cnt<offset; cnt++)
{
// cout << cnt << endl;
ins >> letter;
// outs<< letter;
}
for (loop = 0; loop<size; loop++)
{
ins >> letter;
outs << letter;
// cout << cnt << " " << loop << " " << letter << endl;
}
ins.close();
outs.close();
//Close the input and output files
ins.close();
outs.close();
cout << "Closed the files, this program is done.\n";
//return 0;
}
string decryptshift(char letter, int key)
{
int newletter;
string eletter = "";
newletter = int(letter) - key;
if (newletter < 97){
newletter = newletter + 26;
}
if (newletter >= 97 && newletter <= 122){
eletter = char(newletter);
}
return eletter;
}
string decryptfileshift(string& file, int key)
{
int loop;
string dfile;
for (loop = 0; loop < file.length(); loop++){
// cout << file[loop] << endl;
dfile = dfile + decryptshift(file[loop], key);
}
return dfile;
}
char cleancharinfile(char letter)
{
char symbol;
char concat;
symbol = tolower(letter);
if ((int(symbol) >= 97) && (int(symbol) <= 122)){
concat = symbol;
}
else{
concat = char("");
}
return concat;
}
bool is_allowed(string mgram, vector<string>& alloweds)
{
bool success = false;
vector<string>::iterator ptr;
for (ptr = alloweds.begin(); ptr < alloweds.end(); ptr++){
if (*ptr == mgram){
success = true;
break;
}
if (*ptr > mgram){
break;
}
}
return success;
}
int last_key(vector<bool> list)
{
int key = 0;
int i;
for (i = 0; i < (int)list.size(); i++)
{
if (list.at(i) == true)
{
key = i;
}
}
cout << "solution found" << endl;
return key;
}
//return 0;
//The number of wrong words in the input file is subject to the number of non-alphabetics such as numericals and uppercase letters. However, uppercase letters are first converted to lowercase for uniformity.