diff --git a/CMakeLists.txt b/CMakeLists.txt index 5909823..c47c3dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,5 @@ -cmake_minimum_required(VERSION 2.6) -project(iching) +cmake_minimum_required(VERSION 3.1) +project(iching VERSION 1.0.0 LANGUAGES CXX) add_subdirectory(src) +#add_subdirectory(tests) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4e7e21f..0fdde31 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,7 +2,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wextra -g") find_package(Boost 1.66 COMPONENTS system program_options REQUIRED) include_directories(${Boost_INCLUDE_DIR}) -add_executable(iching main.cc hexagram.cc translator.cc) +add_executable(iching main.cc hexagram.cc translator.cc util.cc) target_link_libraries(iching LINK_PUBLIC ${Boost_LIBRARIES}) install(TARGETS iching RUNTIME DESTINATION bin) diff --git a/src/hexagram.cc b/src/hexagram.cc index 596ade1..3f8813b 100644 --- a/src/hexagram.cc +++ b/src/hexagram.cc @@ -23,12 +23,12 @@ const char* TRIGRAMS[NUM_TRIGRAMS][NUM_TRIGRAM_LINES] = [ EARTH ] = { BROKEN, BROKEN, BROKEN } }; -Trigram Hexagram::lower() +Trigram Hexagram::lower() const { return this->_lower; } -Trigram Hexagram::upper() +Trigram Hexagram::upper() const { return this->_upper; } diff --git a/src/hexagram.h b/src/hexagram.h index ab958b9..6b4da61 100644 --- a/src/hexagram.h +++ b/src/hexagram.h @@ -18,8 +18,12 @@ class Hexagram _upper(upper), _lower(lower), _value(value) {} - Trigram upper(); - Trigram lower(); + Hexagram(const Hexagram& hexagram) : + _upper(hexagram.upper()), + _lower(hexagram.lower()), + _value(hexagram.value()) {} + Trigram upper()const; + Trigram lower() const; unsigned value() const; bool operator <(const Hexagram& hexagram) const; string str(); diff --git a/src/lexer.h b/src/lexer.h new file mode 100644 index 0000000..0604539 --- /dev/null +++ b/src/lexer.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include + +using std::vector; +using std::string; + +namespace Lexer +{ + vector strip_lines(const string& encoded_or_fname) + { + vector lines; + std::stringstream ss(encoded_or_fname); + string line = ""; + + while (std::getline(ss, line, '\n')) + lines.push_back(line); + + return lines; + } +} diff --git a/src/main.cc b/src/main.cc index 74d7bd4..476a9eb 100644 --- a/src/main.cc +++ b/src/main.cc @@ -5,6 +5,7 @@ #include "translator.h" +using std::cerr; using std::cout; using std::endl; @@ -56,12 +57,12 @@ int main(int argc, char** argv) po::notify(vm); } catch(po::error& e) { - std::cerr << "ERROR: " << e.what() << std::endl << std::endl; - std::cerr << desc << std::endl; + cerr << "ERROR: " << e.what() << std::endl << std::endl; + cerr << desc << std::endl; return ERROR_IN_COMMAND_LINE; } } catch(std::exception& e) { - std::cerr << "Unhandled Exception reached the top of main: " + cerr << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit" << std::endl; return ERROR_UNHANDLED_EXCEPTION; diff --git a/src/parser.h b/src/parser.h new file mode 100644 index 0000000..fd42f6d --- /dev/null +++ b/src/parser.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include "hexagram.h" + +using std::vector; + +namespace Parser +{ + static vector lines_to_hexagrams(const vector& lines) + { + vector continuous_hexagrams(NUM_HEXAGRAM_LINES); + int i = 0; + for (const string& line : lines) { + i = i % NUM_HEXAGRAM_LINES == 0 ? 0 : i; + continuous_hexagrams[i] += line; + i += 1; + } + + vector hexagrams; + for (size_t offset = 0; offset < continuous_hexagrams[0].length(); offset += HEXAGRAM_WIDTH) { + string hexagram = ""; + for (const string& line : continuous_hexagrams) { + for (size_t j = offset; j < offset + HEXAGRAM_WIDTH; j++) + hexagram += line[j]; + hexagram += "\n"; + } + hexagrams.push_back(hexagram); + } + + return hexagrams; + } +} diff --git a/src/translator.cc b/src/translator.cc index ebcd0e4..a84a1f8 100644 --- a/src/translator.cc +++ b/src/translator.cc @@ -5,88 +5,48 @@ #include #include #include -#include -#include - -#include -#include -#include -#include #include "hexagram.h" +#include "lexer.h" +#include "parser.h" -using namespace boost::archive::iterators; - -using std::cerr; using std::cout; using std::endl; using std::ifstream; using std::map; using std::pair; -using std::vector; static size_t MAX_WIDTH = 80; -static string B64_CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static map KEYMAP; +string BASE64_CHARACTER_ORDERING = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static void build_keymap() { int i = 0; - for (const char& c : B64_CHARACTERS) { + for (const char& c : BASE64_CHARACTER_ORDERING) { KEYMAP.insert(pair(c, HEXAGRAMS[i])); i += 1; } } -static string b64_encode(string msg) -{ - std::stringstream os; - typedef base64_from_binary> base64_text; - - std::copy( - base64_text(msg.c_str()), - base64_text(msg.c_str() + msg.size()), - std::ostream_iterator(os)); - return os.str(); -} - -static string b64_decode(const string& msg) -{ - typedef transform_width>, 8, 6> ItBinaryT; - string output = ""; - string padded = msg; - - try { - size_t num_pad_chars((4 - msg.size() % 4) % 4); - padded.append(num_pad_chars, '='); - size_t pad_chars(std::count(padded.begin(), padded.end(), '=')); - std::replace(padded.begin(), padded.end(), '=', 'A'); - std::string output(ItBinaryT(padded.begin()), ItBinaryT(padded.end())); - output.erase(output.end() - pad_chars, output.end()); - return output; - } catch (std::exception const& e) { - cerr << "Exception caught: " << e.what() << endl; - } - - return output; -} - -string build_hexagram_output(vector& hexagrams, const string& delimiter) +string build_hexagram_output(const vector& hexagrams, const string& delimiter) { string repr = ""; vector continuous_hexagrams(NUM_HEXAGRAM_LINES); size_t offset = 0; size_t line_pos = 0; - for (Hexagram& hexagram: hexagrams) { + for (const Hexagram& hexagram: hexagrams) { if (line_pos >= MAX_WIDTH) { - for (int i = 0; i < NUM_HEXAGRAM_LINES; i++) + for (int i = 0; i < NUM_HEXAGRAM_LINES; i++) { continuous_hexagrams.push_back(""); + } + offset += NUM_HEXAGRAM_LINES; line_pos = 0; } - string h = hexagram.str(); + string h = Hexagram(hexagram).str(); size_t pos = 0; string token; @@ -99,29 +59,28 @@ string build_hexagram_output(vector& hexagrams, const string& delimite line_pos += HEXAGRAM_WIDTH; } - for (const string& line: continuous_hexagrams) + for (const string& line: continuous_hexagrams) { repr += line + "\n"; + } return repr; } -static int random_generator(int i) -{ - return std::rand() % i; -} - string Translator::encode(const string& input, bool shuffle) { if (shuffle) { std::srand(unsigned(std::time(0))); - std::random_shuffle(B64_CHARACTERS.begin(), B64_CHARACTERS.end(), random_generator); - cout << "KEY: " << B64_CHARACTERS << endl; + std::random_shuffle( + BASE64_CHARACTER_ORDERING.begin(), + BASE64_CHARACTER_ORDERING.end(), + Util::Random::random_generator); + cout << "KEY: " << BASE64_CHARACTER_ORDERING << endl; build_keymap(); } else { build_keymap(); } - string b64_encoded = b64_encode(input); + string b64_encoded = Util::Base64::b64_encode(input); vector hexagrams; for (const char& c : b64_encoded) { @@ -131,62 +90,28 @@ string Translator::encode(const string& input, bool shuffle) return build_hexagram_output(hexagrams, "\n"); } -static vector strip_lines(const string& encoded_or_fname) -{ - vector lines; - std::stringstream ss(encoded_or_fname); - string line = ""; - - while (std::getline(ss, line, '\n')) - lines.push_back(line); - - return lines; -} - -static vector lines_to_hexagrams(const vector& lines) -{ - vector continuous_hexagrams(NUM_HEXAGRAM_LINES); - int i = 0; - for (const string& line : lines) { - i = i % NUM_HEXAGRAM_LINES == 0 ? 0 : i; - continuous_hexagrams[i] += line; - i += 1; - } - - vector hexagrams; - for (size_t offset = 0; offset < continuous_hexagrams[0].length(); offset += HEXAGRAM_WIDTH) { - string hexagram = ""; - for (const string& line : continuous_hexagrams) { - for (size_t j = offset; j < offset + HEXAGRAM_WIDTH; j++) - hexagram += line[j]; - hexagram += "\n"; - } - hexagrams.push_back(hexagram); - } - - return hexagrams; -} - -string Translator::decode(const string& input, string key) +string Translator::decode(const string& input, const string& key) { if (key != "") { - B64_CHARACTERS = key; + BASE64_CHARACTER_ORDERING = key; build_keymap(); } else { build_keymap(); } - vector hexagrams = lines_to_hexagrams(strip_lines(input)); + + vector hexagrams = Parser::lines_to_hexagrams(Lexer::strip_lines(input)); string b64 = ""; for (const string& hexagram: hexagrams) { map::iterator it; for (it = KEYMAP.begin(); it != KEYMAP.end(); it++) { string hex_str = it->second.str(); + if (hex_str != "" && hex_str == hexagram) { b64 += it->first; } } } - return b64_decode(b64); + return Util::Base64::b64_decode(b64); } diff --git a/src/translator.h b/src/translator.h index 403c7cb..7ecde64 100644 --- a/src/translator.h +++ b/src/translator.h @@ -2,10 +2,12 @@ #include +#include "util.h" + using std::string; namespace Translator { string encode(const string& input, bool shuffle = false); - string decode(const string& input, string key = ""); + string decode(const string& input, const string& key = ""); } diff --git a/src/util.cc b/src/util.cc new file mode 100644 index 0000000..b9916ff --- /dev/null +++ b/src/util.cc @@ -0,0 +1,69 @@ +#include "util.h" + +#include +#include +#include + +#include +#include +#include +#include + +using namespace boost::archive::iterators; +using std::cerr; +using std::cout; +using std::endl; + +int Util::Random::random_generator(int i) +{ + return std::rand() % i; +} + +string & Util::String::rtrim(const string& s, const char* t) +{ + + return string(s).erase(s.find_last_not_of(t) + 1); +} + +string & Util::String::ltrim(const string& s, const char* t) +{ + return string(s).erase(0, s.find_first_not_of(t)); +} + +string & Util::String::trim(const string& s, const char* t) +{ + return Util::String::ltrim(Util::String::rtrim(s, t), t); +} + +string Util::Base64::b64_decode(const string& msg) +{ + typedef transform_width>, 8, 6> ItBinaryT; + string output = ""; + string padded = msg; + + try { + size_t num_pad_chars((4 - msg.size() % 4) % 4); + padded.append(num_pad_chars, '='); + size_t pad_chars(std::count(padded.begin(), padded.end(), '=')); + std::replace(padded.begin(), padded.end(), '=', 'A'); + std::string output(ItBinaryT(padded.begin()), ItBinaryT(padded.end())); + output.erase(output.end() - pad_chars, output.end()); + return output; + } catch (std::exception const& e) { + cerr << "Exception caught: " << e.what() << endl; + } + + return output; +} + +string Util::Base64::b64_encode(const string& msg) +{ + std::stringstream os; + typedef base64_from_binary> base64_text; + + std::copy( + base64_text(msg.c_str()), + base64_text(msg.c_str() + msg.size()), + std::ostream_iterator(os)); + return os.str(); +} diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..a36389e --- /dev/null +++ b/src/util.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +using std::string; + +namespace Util +{ + namespace Random + { + int random_generator(int i); + } + + namespace Base64 + { + string b64_encode(const string& msg); + string b64_decode(const string& msg); + } + + namespace String + { + inline string& rtrim(const string& s, const char* t = " \t\n\r\f\v"); + inline string& ltrim(const string& s, const char* t = " \t\n\r\f\v"); + inline string& trim(const string& s, const char* t = " \t\n\r\f\v"); + } +}