///////////////////////// // // This program reads in a list of hash values and stores them in a // vector. It then reads in a second list of hashes and compares each // to the first list. If any match, a message is output that says so. // It is the same as project 4, but using linked lists instead of vectors // in the case file. #include #include #include #include #include using namespace std; void print_instructions(); ///////////////////////////////// // // Hash set class // class hash_set { public: void load_hashes(); void print_hashes(); void print_hash_set(); int number_of_hashes(); void print_comments(); void add_hash(string); vector get_hashes(); private: vector comments; vector hashes; }; // This method askes for a file name, then opens the file, // reads the comments from the first three lines and the // hashes after that. It stores the comment results in order // in the comments vector, and the hashes in any order in the // hashes vector. Any old values already in the vectors are // overwritten. void hash_set::load_hashes(){ string current_value, header_1, header_2, header_3; string hashfilename; ifstream inputfile; // Clear the hashes and comments files, in case of double load comments.clear(); hashes.clear(); // Get the filename to be used cout << "Please enter the name of the hash file: "; cin >> hashfilename; // Try and open that file. Die if it fails. inputfile.open(hashfilename.c_str()); if (!inputfile){ cerr << "File: " << hashfilename << " not found. Aborting." << endl; exit(1); } // now read the 3 comment lines into the comments vector // make sure that the order is the same getline(inputfile, header_1); getline(inputfile, header_2); getline(inputfile, header_3); comments.push_back(header_1); comments.push_back(header_2); comments.push_back(header_3); // Read the remaining values and enter them into the vector while (inputfile >> current_value){ hashes.push_back(current_value); } }; // This method prints the hashes neatly on the screen void hash_set::print_hashes(){ for (int i = 0; i < hashes.size(); i++){ cout << hashes[i] << endl; } }; // This method prints the comments from the file neatly // on the screen void hash_set::print_comments(){ for (int i=0; i < comments.size(); i++){ cout << comments[i] << endl; } }; // This method prints the whole hash set out // Comments first, and then the hashes void hash_set::print_hash_set(){ print_comments(); print_hashes(); } // This method returns an integer that is the number // of hashes in the hash set int hash_set::number_of_hashes(){ return hashes.size(); }; // This method adds the hash given as a parameter to the hash set void hash_set::add_hash(string new_hash){ hashes.push_back(new_hash); }; // This method returns the vector containing the hashes vector hash_set::get_hashes(){ return hashes; }; ////////////////////////////////// // // File class // // This is a self-referential class that is used to keep track of // individual files, each of which has a name and a hash class file{ // add friend function reading and writing friend ostream &operator<<(ostream&, file); friend istream &operator>>(istream&, file &); public: file(); file(string, string); void set_name(string); string get_name(); void set_hash(string); string get_hash(); void set_next_file(file *); file * get_next_file(); ~file(); private: string filename; string hash; file * next_file; }; // Default constructor for the file class file::file(){ filename = ""; hash = ""; next_file = NULL; } // Constructor to allow setting initial values for name // and hash file::file(string initial_name, string initial_hash){ filename = initial_name; hash = initial_hash; next_file = NULL; } // Set the name of the file void file::set_name(string new_name){ filename = new_name; } // Find out what the name of the file is string file::get_name(){ return filename; } // Set the value of the hash void file::set_hash(string new_hash){ hash = new_hash; } // Find the value of the hash string file::get_hash(){ return hash; } // Set the next file void file::set_next_file(file * new_file){ next_file = new_file; } // Get the next file file * file::get_next_file(){ return next_file; } // Desctructor - nothing really needed here file::~file(){ } // overload the output operator ostream &operator<<(ostream &output, file f) { output << f.filename << " " << f.hash; return output; } // overload the input operator istream &operator>>(istream &input, file &f){ input >> f.filename >> f.hash; return input; } // ////////////////////////////////// ///////////////////////////////// // // Case file class // class case_file{ public: case_file(); void load_case_file(); void print_file_names(); void print_file_hashes(); void print_comments(); void print_case_file(); int number_of_files(); void add_file(string, string); int find_hash_matches(hash_set); ~case_file(); private: file * file_list; void add_file_to_list(file *); vector comments; }; case_file::case_file(){ file_list = NULL; } // This method askes for a file name, then opens the file, reads the // comments from the first three lines and the file names and hashes // after that. It stores the comment results in order in the comments // vector, and the hashes in a linked list of file objects void case_file::load_case_file(){ string casefilename; ifstream inputfile; string header_1,header_2, header_3, current_file_string, current_hash_string; file * new_file, * temp, * next; // Get the filename to be used cout << "Please enter the name of the case file : "; cin >> casefilename; // Try and open that file. Die if it fails. inputfile.open(casefilename.c_str()); if (!inputfile){ cerr << "File: " << casefilename << " not found. Aborting." << endl; exit(1); } // now read the 3 comment lines into the comments vector // make sure that the order is the same getline(inputfile, header_1); getline(inputfile, header_2); getline(inputfile, header_3); comments.push_back(header_1); comments.push_back(header_2); comments.push_back(header_3); // clear the linked list in case it already has values on it temp = file_list; while (temp != NULL) { next = temp->get_next_file(); delete (temp); temp = next; } file_list = NULL; // Read the remaining values and enter them into the vector while (inputfile >> current_file_string >> current_hash_string){ new_file = new file; new_file->set_name(current_file_string); new_file->set_hash(current_hash_string); add_file_to_list(new_file); } }; // This method prints the comments from the file neatly // on the screen void case_file::print_comments(){ for (int i=0; i < comments.size(); i++){ cout << comments[i] << endl; } }; // This method prints the names of the files neatly // on the screen void case_file::print_file_names(){ file * temp_file_ptr = file_list; while (temp_file_ptr != NULL){ cout << temp_file_ptr->get_name() << endl; temp_file_ptr = temp_file_ptr->get_next_file(); } }; // This method prints the hashes of the files neatly // on the screen void case_file::print_file_hashes(){ file * temp_file_ptr = file_list; while (temp_file_ptr != NULL){ cout << temp_file_ptr->get_hash() << endl; temp_file_ptr = temp_file_ptr->get_next_file(); } }; // This methos prints the entire case file on the screen, // comments first, and then traverse the file list and use cout // to print each file object void case_file::print_case_file(){ print_comments(); file * temp_file_ptr = file_list; while (temp_file_ptr != NULL){ cout << *temp_file_ptr << endl; temp_file_ptr = temp_file_ptr->get_next_file(); } }; // this method returns the number of files in the case file int case_file::number_of_files(){ int count = 0; file * temp_file_ptr = file_list; while (temp_file_ptr != NULL){ count++; temp_file_ptr = temp_file_ptr->get_next_file(); } return count; }; // This method takes a file name and a file hash as parameters // and then adds the name and hashes to the case vectors void case_file::add_file(string new_name, string new_hash){ file * temp_file = new file(new_name, new_hash); add_file_to_list(temp_file); }; // This method takes a vector of strings that contains hashes as // a parameter. It then finds all case hashes that match, and prints those // to the screen. It returns the total number of matches. int case_file::find_hash_matches(hash_set known_hashes){ int matches = 0; vector given_hashes = known_hashes.get_hashes(); file * temp_file_ptr; for (int i=0; i < given_hashes.size(); i++){ temp_file_ptr = file_list; while (temp_file_ptr != NULL){ if (temp_file_ptr->get_hash() == given_hashes[i]){ cout << "File: " << temp_file_ptr->get_name() << " matches known hashes with hash: " << given_hashes[i] << endl; matches++; } temp_file_ptr = temp_file_ptr->get_next_file(); } } return matches; }; // A deconstructor to delete the linked list when the // case file object goes away case_file::~case_file(){ file * temp, * next; temp = file_list; while (temp != NULL) { next = temp->get_next_file(); delete (temp); temp = next; } file_list = NULL; } // This is a private function that will add a pointer to a file to the // file list. I add it to the head void case_file::add_file_to_list(file * new_file){ new_file->set_next_file(file_list); file_list = new_file; } /////////////////////////////// // // Main for testing the file class // /* int main (){ file * test = NULL; test = new file(); test->set_name("Test"); cout << "File name should be 'Test' and it is: " << test->get_name() << endl; test->set_hash("9eb8c6d611097c8fba484d399d7d9e97"); cout << "Hash should be 9eb8c6d611097c8fba484d399d7d9e97 and it is: " << test->get_hash() << endl; // Make sure the friend functions work cout << "The next two lines should be the same: " << endl; cout << "Test 9eb8c6d611097c8fba484d399d7d9e97" << endl; cout << *test << endl; cout << "Type the two words 'foo bar' and hit enter:"; cin >> *test; cout << "The next line should say 'foo bar':" << endl; cout << *test << endl; // Make sure pointer operations work file * foo = new file(); test->set_next_file(foo); cout << "The next file value should be " << foo << " and it is: " << test->get_next_file() << endl; } */ //////////////////////////////// // // Main for testing the case_file class // int main(){ string newfile = "new.txt", newhash = "3f508486d0b740c8e15a5770e0f29581"; int size, found; cout << "Using case_file main" << endl; hash_set test_hashes; test_hashes.load_hashes(); test_hashes.add_hash(newhash); case_file test_case; test_case.load_case_file(); test_case.print_comments(); test_case.print_file_names(); test_case.print_file_hashes(); size = test_case.number_of_files(); cout << "Size should be 6 and it is " << size << endl; test_case.add_file(newfile, newhash); test_case.print_case_file(); found = test_case.find_hash_matches(test_hashes); cout << "Found should be 2 and it is " << found << endl; return 0; } /* int main (){ case_file case_file; hash_set known_hashes; int matches = 0; char input; bool done = 0; while (!done){ print_instructions(); cin >> input; switch (input){ case 'H': case 'h': known_hashes.load_hashes(); break; case'C': case 'c': case_file.load_case_file(); break; case 'M': case 'm': matches = case_file.find_hash_matches(known_hashes); cout << "Number of matches: " << matches << endl; break; case'D': case 'd': cout << "Hash Set: " << endl; known_hashes.print_hash_set(); cout << endl << endl << endl << endl; cout <<"Case file: " << endl; case_file.print_case_file(); cout << endl; break; case 'Q': case 'q': done = 1; break; default: cout << "Invalid command character" << endl; } } return 0; } */ void print_instructions(){ cout << "This program reads a file containing a set of hashes, " << endl; cout << "then reads a second file consisting of filenames and hashes. " << endl; cout << "It will then identify each file from the second file that match " << endl; cout << "a hash from the first file." << endl << endl; cout << "Menu choices:" << endl; cout << left; cout << setw(5) << "H" << setw(45) << "Load the hash set" << endl; cout << setw(5) << "C" << setw(45) << "Load the case file" << endl; cout << setw(5) << "M" << setw(45) << "Compare the hash set and case file" << endl; cout << setw(5) << "D" << setw(45) << "Print hash set and case file" << endl; cout << setw(5) << "" << setw(45) << "(for debugging)" << endl; cout << setw(5) << "Q" << setw(45) << "Quit the program" << endl; cout << endl << endl << "Your choice: "; }