commit 3f69e0243e8a6572c092c88c43357c18db3252b9 Author: Maximilian Stiefel Date: Sat Mar 31 22:48:48 2018 +0200 First working version of the API supporting DESV. diff --git a/dictcc/desv.h b/dictcc/desv.h new file mode 100644 index 0000000..dfd1c0d --- /dev/null +++ b/dictcc/desv.h @@ -0,0 +1,25 @@ +#ifndef DICTCC_DESV_INCLUDED +#define DICTCC_DESV_INCLUDED + +// Dictcc API +#include "dict.h" + +namespace dictcc +{ + class desv : public dict + { + // TODO: Implement specifics of the language here. + public: + desv(); + ~desv() + {} + }; + + desv::desv() + { + d_suburl = "desv"; + } + +} // namespace dictcc + +#endif // DICTCC_DESV_INCLUDED diff --git a/dictcc/dict.h b/dictcc/dict.h new file mode 100644 index 0000000..09aa3a4 --- /dev/null +++ b/dictcc/dict.h @@ -0,0 +1,179 @@ +// STD +#include +#include +#include +#include +#include +#include +// Curl +#include +#include +#include +// Boost +#include +// Dictcc API +#include "types.h" +#include "exceptions.h" + +#ifndef DICTCC_DICT_INCLUDED +#define DICTCC_DICT_INCLUDED + +namespace dictcc +{ + /*! \brief Base dictionary class. + */ + class dict + { + protected: + static const std::string URL_HTTPS; + static const std::string URL_REST; + static const std::string QUERYA; + static const std::string QUERYB; + static const std::string QUERYC; + static const std::string SEPERATOR; + + protected: + /*! \brief Word list corresponding to one language. + */ + word_list_t d_wordsl0; + /*! \brief Word list corresponding to one language. + */ + word_list_t d_wordsl1; + curlpp::Easy d_request; + curlpp::Cleanup d_cleaner; + lang_t d_langs; + std::string d_suburl; + + protected: + void parse_answer(const std::ostringstream& os, const std::string& query, word_list_t& vec); + + protected: + dict(){} + + public: + static dict* create(const std::string langs); + virtual ~dict(){} + + public: + search_t search(std::string word); + static std::string langs2str(const lang_t& lt); + static lang_t str2langs(const std::string& str); + }; + + const std::string dict::URL_HTTPS = "https://"; + const std::string dict::URL_REST = ".dict.cc/?s="; + const std::string dict::QUERYA = "c1Arr = new Array"; + const std::string dict::QUERYB = "c2Arr = new Array"; + const std::string dict::QUERYC = ");"; + const std::string dict::SEPERATOR = "\",\""; + + void dict::parse_answer(const std::ostringstream& os, const std::string& query, word_list_t& vec) + { + std::string page = os.str(); + auto lstart = page.find(query); + auto lend = page.find(QUERYC, lstart); + // No results found -> throw an exception + if(lstart == -1) + throw(dict_no_results(__FILE__, __LINE__)); + lstart += query.size(); + // Scroll to the first character + while( (page[lstart] == '\"') || (page[lstart] == ',') || (page[lstart] == '(') ) + lstart++; + // Scroll to the last character + while( (page[lstart] == '\"') || (page[lstart] == ',') || (page[lstart] == '(') ) + lend--; + // Get the line. + std::string line = page.substr(lstart, lend-lstart); + // Split it. + boost::split(vec, line, boost::is_any_of(SEPERATOR), boost::token_compress_on); + // Last element is always empty. + vec.pop_back(); + // Make sure, that the string termination is present. + for (std::string& str : vec) { + if (str[str.size()-1] != '\0' ) { + str.append("\0"); + } + } + } + + search_t dict::search(std::string word) + { + std::ostringstream answer; + // Perform HTTP request with SSL below. + try { + std::string dict_req = URL_HTTPS + d_suburl + URL_REST + word; + curlpp::options::Url url(dict_req); + d_request.setOpt(url); + answer << d_request; + } catch(curlpp::RuntimeError &e) { + std::ostringstream ss; + ss << e.what() << "(curlpp::RuntimeError)."; + throw(dict_libcurl_error(__FILE__, __LINE__, ss.str())); + } catch(curlpp::LogicError &e) { + std::ostringstream ss; + ss << e.what() << "(curlpp::LogicError)."; + throw(dict_libcurl_error(__FILE__, __LINE__, ss.str())); + } + // Convert request into word lists language one and language two respectively. + try { + parse_answer(answer, QUERYA, d_wordsl0); + parse_answer(answer, QUERYB, d_wordsl1); + } catch (dict_no_results& e) { + // The parsing might go wrong. + e << std::string("Could not find ") + std::string("\"") + word + std::string("\"."); + throw; + } + // Return a pair of references + return std::make_pair(&d_wordsl0, &d_wordsl1); + } + + inline std::string dict::langs2str(const lang_t& lt) + { + // TODO: Add new languages here. + std::vector str = {"DESV", "DEEN"}; + if (lt >= str.size()) { + throw(dict_lang_error(__FILE__, __LINE__)); + } + return str[lt]; + } + + inline lang_t dict::str2langs(const std::string& str) + { + if (str == "DESV") { + return DESV; + } else if ( str == "DEEN") { + return DEEN; + } else { + throw(dict_lang_error(__FILE__, __LINE__)); + } + } + + class desv : public dict + { + // TODO: Implement specifics of the language here. + public: + desv(); + ~desv() + {} + }; + + desv::desv() + { + d_suburl = "desv"; + } + + dict* dict::create(const std::string langs) + { + lang_t l = str2langs(langs); + // TODO: Add new languages here + switch (l) { + case DESV: + return new desv; + break; + default: + throw(dict_lang_error(__FILE__, __LINE__)); + } + } +} // namespace dictcc + +#endif // DICTCC_DICT_INCLUDED diff --git a/dictcc/exceptions.h b/dictcc/exceptions.h new file mode 100644 index 0000000..5265ae4 --- /dev/null +++ b/dictcc/exceptions.h @@ -0,0 +1,77 @@ +#include +#include + +#ifndef DICTCC_EXCEPTIONS_INCLUDED +#define DICTCC_EXCEPTIONS_INCLUDED + +namespace dictcc +{ + /*! \brief Exception class to be thrown if there is a general problem with the dictionary. + */ + class dict_exception : public std::exception + { + private: + std::string d_file; + int d_line; + + protected: + std::string d_msg; + + public: + dict_exception(const std::string file, const int line, const std::string msg) + : d_msg(msg), d_file(file), d_line(line) + { + std::ostringstream os; + os << d_file << ": " << d_line << ": " << d_msg; + d_msg = os.str(); + } + /*! \brief Get the exception identifier. + */ + const char* what() const noexcept + { + return d_msg.c_str(); + }; + /*! \brief Get the naked file where the exception happened. + */ + std::string file() const noexcept {return d_file;} + /*! \brief Get line where the exception happened. + */ + int line() const noexcept {return d_line;} + }; + + /*! \brief Exception class to be thrown if no results have been found for a search. + */ + class dict_no_results : public dict_exception + { + public: + dict_no_results(const std::string file, const int line, const std::string msg = "") + : dict_exception(file, line, msg) {} + /*! \brief Change message content of a exception, that has been thrown. + */ + void operator<<(const std::string& new_msg) noexcept + { + this->d_msg += new_msg; + } + }; + + /*! \brief Exception class to be thrown if there is a libcurl issue. + */ + class dict_libcurl_error : public dict_exception + { + public: + dict_libcurl_error(const std::string file, const int line, const std::string msg) + : dict_exception(file, line, msg) {} + }; + + /*! \brief Exception class to be thrown if there is a libcurl issue. + */ + class dict_lang_error : public dict_exception + { + public: + dict_lang_error(const std::string file, const int line, const std::string msg = "Language is not supported.") + : dict_exception(file, line, msg) {} + }; + +} // namespace dictcc + +#endif // DICTCC_EXCEPTIONS_INCLUDED diff --git a/dictcc/types.h b/dictcc/types.h new file mode 100644 index 0000000..0b3799a --- /dev/null +++ b/dictcc/types.h @@ -0,0 +1,26 @@ +#include +#include +#include +#include + +#ifndef DICTCC_TYPES_INCLUDED +#define DICTCC_TYPES_INCLUDED + +namespace dictcc +{ + /*! \brief List of words in one language. + */ + typedef std::vector word_list_t; + /*! \brief Pair of two word lists with corresponding word/sentence pairs (translations) resulting from a search string. + */ + typedef std::pair search_t; + /*! \brief Supported language pairs. + */ + typedef enum + { + DESV, + DEEN + } lang_t; +} // namespace dictcc + +#endif // DICTCC_TYPES_INCLUDED