/*===============================================================================================================
Program Overview: This program is designed to take an input file, translate it to an appropriate Ceaser cipher
and then to take metrics on the resulting application of data that is input from the tranlation output file.
Set theoretic estimations for sets are then applied to the information that results and predictions of the
correct shift are then made as each set of rule based sets is specified and applied to the problem.
Variables:
Functions Called: createinput(ifile, ofile)
createciphter(key, ifile, ofile)
Command Line Variables: -k int Sets the key offset
-off int Sets the offset in the file
-l int Sets the length of the file to process
-m float Sets the value of the metric error
-i string Sets the input file path, file name without extender - assumed to be .txt
-o string Sets the output file path, no file name - just path
-stop char Sets the stop criterion: l for length, m for metric error
===============================================================================================================*/
/*===============================================================================================================
Assumptions about the Ceaser Cipher:
1. The corpus is in English only
2. The input contains only alphabetic charaters - there are no spaces
===============================================================================================================*/
// 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>
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
double mi = 26; //Figures m_i
char loopletter;
float percent;
float temp; //A temporary variable
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 an error less than or equal to " << 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 output 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;
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";
}
// cout << "While " << mi << ">" << m << endl;
while(mi > m)
{
trimfile(ofile2,ofile2,off,len);
totalcnt = lettercount(single, ofile2, ofile2);
// cout << "Total count = " << totalcnt << "\n\n";
for(count=0;count<26;count++)
{
loopletter = 97 + count;
if(totalcnt==0) //Used the first time through the loop when totalcnt = 0
{
totalcnt++;
}
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;
total = 0;
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";
temp = float(countunique(single,26));
if(temp == 0) //Eliminates errors first time through the loop
{
temp = temp + 1;
}
mi = float(abs(final - key))/temp;
// cout << "mi = " << mi << " and m = " << m << endl;
// cout << "Testing for " << len << " letter(s). \n\n\n";
// outs << ifile2 << "," << off << "," << key << "," <<final << "," << len << "," << mi << "," << m << endl;
len++;
}
// cout << "Out of the loop\n\n";
// dicount=digram(two, ofile2);
outs << ifile2 << "," << key << "," << final << "," << len << "," << off << "," << m << endl;
outs.close();
return 0;
}
/*=================================================================================================================
Function createinput(ifile, ofile)
Created 9/25/2003
Function Overview: Takes in a text file and reads input data, removing all non-alphabetic characters. Here it
is assumed that the characters in the file are intended for use as the corpus of the cipher translation. All
spaces are removed, and then all instances of upper case letters are translated to lower case in order to make
the data consistant.
Variables used:
ch char Holds the character read in and manipulated for later use
count int Holds the count of the number of words read
table string Holds the value of in input variable for reading a file input
tablein string Holds the value of a string used for a file
outfile Holds the string value of an ouput file
singlefreq Holds the counts of letters in the file to be processed
single Pointer to the singlefreq structure
Functions called: None
===================================================================================================================*/
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";
}
/*=================================================================================================================
Function createcipher(int key, string ifile, string ofile)
Created 9/25/2003
Function Overview: Takes a text input file and translates it into a Ceaser Cipher output that is shifted by
modulo 26 of the input value.
Variables used:
ch char Holds the character read in and manipulated for later use
offset int Holds the modulo offset for encoding
val int Used as a flag for a while loop
table string Holds the value of in input variable for reading a file input
tablein string Holds the value of a string used for a file
outfile Holds the string value of an ouput file
Functions called: None
===================================================================================================================*/
void createcipher(int key, string ifile, string ofile)
{
unsigned char ch; //Unsigned because going over 128 in ASCII during a calculation results in a negative number
// and the ASCII number will then appear as negative if the offset added to the letter
// representation is greater than 127 Hex.
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 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";
}
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";
}
/*=================================================================================================================
Function lettercount(int *pointer)
Created 9/25/2003
Function Overview: Takes an input file and counts all of the letters that are found in the file. This function
assumes that the input file contains ONLY ASCII values for lower case letters. It uses a
pointer that directs the function to the first storage location of an array that will
contain slots for each character in the alphabet. It then reads in each value and increments
the counter for each letter as it recognizes the letter. Note that the offset of the letter
read from 'a' is calculated and used as the array index.
Variables used:
char target Holds the character read in and manipulated for later use
offset int Holds the array offset for incrementing the count in the array
lettercount int Contains the total number of letters in the file
pointer int* Points to the location of the array for letter counts
table string Holds the value of in input variable for reading a file input
tablein string Holds the value of a string used for a file
outfile Holds the string value of an ouput file
Functions called: None
Notes: Lower case letters are found from ASCII 97 ('a') to ASCII 122 ('z')
===================================================================================================================*/
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;
}
/*=================================================================================================================
Function singleton(int *pointer, int size)
Created 9/25/2003
Function Overview: Takes an input array and finds the greatest count from among the input values. This function
will input an arbitrary sized array and goes from the first location, pointed to by the pointer
and successively checks each value. It runs in order n time.
Variables used:
loop int Holds the loop count
highest int Holds the highest count found in the array
tempcnt int Contains the number read by the count going through the array at that time
pointer int* Points to the location of the array for counts
offset int Holds the value of the letter what was found to have the highest count.
Functions called: None
Notes: Lower case letters are found from ASCII 97 ('a') to ASCII 122 ('z')
===================================================================================================================*/
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
/* Loop from the first spot in the array to the final spot, as given by size,
and check the value of the letter frequency for that particular encoded letter.
If the value is the highest yet seen, then record that value and the offset.
*/
for(loop=0;loop<size;loop++)
{
tempval = letter[loop];
if(tempval > highest)
{
highest = tempval;
offset = loop;
}
}
return offset;
}
/*=================================================================================================================
Function digram(pointer, ifile)
Created 9/25/2003
Function Overview:
Variables used:
ch char Holds the character read in and manipulated for later use
Functions called: None
===================================================================================================================*/
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;
}
/*=================================================================================================================
Function countunique(*array, size)
Created 8/4/05
Function Overview: Counts the number of unique elements stored in an array of size 'size' located at 'array'.
Each non zero count indicates that an element exists.
Variables used:
Name Type Use
------ ---- ------------------------------------------------------------------------------------------------
*array int Points to the location of the array in memory
size int The size of the array for counting
cnt int The number of non zero array locations (and hence the number of unique elements seen)
loop int An internal loop counter
Functions called: None
===================================================================================================================*/
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;
}
/*=================================================================================================================
Function trimfile(ifile, ofile, offset, size)
Created 8/4/05
Function Overview: Reads in a file, then trims the file starting at the 'offset' for 'size' characters and puts
the result in ofile.
Variables used:
Name Type Use
------ ---- ------------------------------------------------------------------------------------------------
cnt int A loop counter
ifile string Holds the input file path
letter char Holds the letter read from the input file
loop int A loop counter
offset int Holds the offset for the first letter of the resulting file
ofile string Holds the output file path
size int Holds the size of the final file, in symbols
Functions called: None
===================================================================================================================*/
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;
}
if(size!=-1)
{
for(loop=0;loop<size;loop++)
{
ins >> letter;
outs << letter;
// cout << cnt << " " << loop << " " << letter << endl;
}
}
else
{
while(!ins.eof())
{
ins >> letter;
outs << letter;
}
}
ins.close();
outs.close();
}
/*=================================================================================================================
Function name(i/o list)
Created date
Function Overview: Takes in a text file and reads input data, removing all non-alphabetic characters. Here it
is assumed that the characters in the file are intended for use as the corpus of the cipher translation. All
spaces are removed, and then all instances of upper case letters are translated to lower case in order to make
the data consistant.
Variables used:
Name Type Use
------ ---- ------------------------------------------------------------------------------------------------
Functions called: None
===================================================================================================================*/