/* Copyright 2015-2017 Amebis This file is part of ZRCola. ZRCola is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. ZRCola is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with ZRCola. If not, see . */ #pragma once #include #include #include #include #include #include #include #include #include #include #include namespace ZRCola { /// /// Source database /// class DBSource { public: /// /// Character sequence /// class charseq { public: int rank; ///< Sequence rank std::wstring str; ///< Sequence string inline charseq() { } inline charseq(_In_ int _rank, _In_z_ const wchar_t *_str) : rank(_rank), str (_str) { } /// /// Functor to compare two sequences by `rank`, and `str` members respectively /// struct less_rank_str { inline bool operator()(_In_ const charseq& a, _In_ const charseq& b) const { if (a.rank < b.rank) return true; else if (a.rank > b.rank) return false; else if (a.str < b.str ) return true; else return false; } }; }; /// /// Translation /// class translation { public: wchar_t chr; ///< Composed character charseq decomp; ///< Decomposed sequence }; /// /// Key sequence /// class keyseq { public: /// /// Key code /// struct keycode { wchar_t key; ///< Key bool shift; ///< Shift modifier bool ctrl; ///< Ctrl modifier bool alt; ///< Alt modifier /// /// Translates keycode from Slovenian to English keyboard /// inline static wchar_t translate_slen(_In_ wchar_t key) { switch (key) { case L'Z': return L'Y'; case L'Y': return L'Z'; case 191: return 189; case 189: return 191; default : return key; } } }; public: wchar_t chr; ///< Character std::vector seq; ///< Key sequence }; /// /// Language /// class language { public: ZRCola::langid_t id; ///< Language ID std::wstring name; ///< Language name }; /// /// Language Character /// class langchar { public: wchar_t chr; ///> Character ZRCola::langid_t lang; ///< Language ID }; /// /// Character group /// class chrgrp { public: int id; ///< Character group ID int rank; ///< Character group rank std::wstring name; ///< Character group name std::wstring chars; ///< Character group characters std::vector show; ///< Bit vector if particular character is displayed initially }; /// /// Character /// class character { public: inline character() { chr = 0; cat.data[0] = 0; cat.data[1] = 0; } inline character(_In_ const character &othr) : chr (othr.chr), cat (othr.cat), desc (othr.desc), terms(othr.terms), rel (othr.rel) { } inline bool operator==(_In_ const character &othr) const { return chr == othr.chr && cat == othr.cat && desc == othr.desc && terms == othr.terms && rel == othr.rel; } inline bool operator!=(_In_ const character &othr) const { return !operator==(othr); } wchar_t chr; ///< Character ZRCola::chrcatid_t cat; ///< Category ID std::wstring desc; ///< Character description std::set terms; ///< Search terms std::wstring rel; ///< Related characters }; /// /// Character bank /// class character_bank : public std::vector > { public: character_bank(); void build_related(); protected: class build_related_worker : public winstd::win_handle { public: build_related_worker(_In_ const character_bank *cb, _In_ size_type from, _In_ size_type to); inline void join() { if (m_h) WaitForSingleObject(m_h, INFINITE); } private: // This class is non-copyable AND non-movable build_related_worker(_Inout_ build_related_worker &othr); build_related_worker(_Inout_ build_related_worker &&othr); build_related_worker& operator=(_Inout_ build_related_worker &othr); build_related_worker& operator=(_Inout_ build_related_worker &&othr); protected: unsigned int process(); static unsigned int __stdcall process(_In_ void *param); protected: const character_bank *m_cb; size_type m_from, m_to; winstd::heap m_heap; }; protected: std::set m_ignore; }; /// /// Character description index key comparator /// struct character_desc_idx_less : public std::binary_function { inline bool operator()(const std::wstring& _Left, const std::wstring& _Right) const { size_t _Left_len = _Left .size(), _Right_len = _Right.size(); int r = _wcsncoll(_Left.c_str(), _Right.c_str(), std::min(_Left_len, _Right_len)); if (r != 0 ) return r < 0; else if (_Left_len < _Right_len) return true; return false; } }; /// /// Character description index /// class character_desc_idx : public std::map, character_desc_idx_less> { public: static void parse_keywords(const wchar_t *str, std::set &terms); void add_keywords(const std::set &terms, wchar_t chr, size_t sub = 0); inline void add_keywords(const wchar_t *str, wchar_t chr, size_t sub = 0) { std::set terms; parse_keywords(str, terms); add_keywords(terms, chr, sub); } void save(ZRCola::textindex &idx) const; protected: inline void add_keyword(const std::wstring &term, wchar_t chr) { iterator idx = find(term); if (idx == end()) { // New keyword. insert(std::make_pair(term, std::vector(1, chr))); } else { // Append to existing keyword. std::vector &val = idx->second; for (auto i = val.cbegin(), i_end = val.cend(); ; ++i) { if (i == i_end) { // End-of-values reached. Append character. val.push_back(chr); break; } else if (*i == chr) { // Character already among the values. break; } } } } }; /// /// Character category /// class chrcat { public: ZRCola::chrcatid_t id; ///> Category ID int rank; ///< Character category rank std::wstring name; ///< Character category name }; /// /// Character tag /// class chrtag { public: wchar_t chr; ///> Character int tag; ///< Tag ID }; /// /// Tag name /// class tagname { public: int tag; ///< Tag ID std::map > names; ///< Names }; public: DBSource(); virtual ~DBSource(); /// /// Opens the database /// /// \param[in] filename File name of the MDB database. /// /// \returns /// - true when open succeeds /// - false otherwise /// bool Open(LPCTSTR filename); /// /// Logs errors in database connections /// void LogErrors() const; /// /// Is recordset at end /// /// \param[out] rs Recordset with results /// /// \returns /// - true when at end /// - false otherwise /// static inline bool IsEOF(const winstd::com_obj& rs) { VARIANT_BOOL eof = VARIANT_TRUE; return FAILED(rs->get_EOF(&eof)) || eof ? true : false; } /// /// Gets number of records in a recordset /// /// \param[out] rs Recordset with results /// /// \returns Number of records /// static inline size_t GetRecordsetCount(const winstd::com_obj& rs) { ADO_LONGPTR count; return SUCCEEDED(rs->get_RecordCount(&count)) ? count : (size_t)-1; } /// /// Splits string to individual keywords /// /// \param[in ] str String /// \param[out] keywords Array of keywords /// /// \returns /// - true when successful /// - false otherwise /// static bool GetKeywords(const wchar_t *str, std::vector< std::wstring > &keywords); /// /// Gets boolean from ZRCola.zrc database /// /// \param[in] f Data field /// \param[out] val Output boolean value /// /// \returns /// - true when successful /// - false otherwise /// bool GetValue(const winstd::com_obj& f, bool& val) const; /// /// Gets integer from ZRCola.zrc database /// /// \param[in] f Data field /// \param[out] val Output integer value /// /// \returns /// - true when successful /// - false otherwise /// bool GetValue(const winstd::com_obj& f, int& val) const; /// /// Gets string from ZRCola.zrc database /// /// \param[in] f Data field /// \param[out] val Output string value /// /// \returns /// - true when successful /// - false otherwise /// bool GetValue(const winstd::com_obj& f, std::wstring& val) const; /// /// Gets encoded Unicode character from ZRCola.zrc database /// /// \param[in] f Data field /// \param[out] chr Output character /// /// \returns /// - true when successful /// - false otherwise /// bool GetUnicodeCharacter(const winstd::com_obj& f, wchar_t& chr) const; /// /// Gets encoded Unicode string from ZRCola.zrc database /// /// \param[in] f Data field /// \param[out] str Output string /// /// \returns /// - true when successful /// - false otherwise /// bool GetUnicodeString(const winstd::com_obj& f, std::wstring& str) const; /// /// Gets language ID from ZRCola.zrc database /// /// \param[in] f Data field /// \param[out] lang Language /// /// \returns /// - true when successful /// - false otherwise /// bool GetLanguage(const winstd::com_obj& f, langid_t& lang) const; /// /// Gets character category ID from ZRCola.zrc database /// /// \param[in] f Data field /// \param[out] cc Character category /// /// \returns /// - true when successful /// - false otherwise /// bool GetChrCat(const winstd::com_obj& f, chrcatid_t& cc) const; /// /// Gets tag names from ZRCola.zrc database /// /// \param[in] f Data field /// \param[out] names Output names /// /// \returns /// - true when successful /// - false otherwise /// bool GetTagNames(const winstd::com_obj& f, LCID lcid, std::list& names) const; /// /// Returns character translations /// /// \param[out] rs Recordset with results /// /// \returns /// - true when query succeeds /// - false otherwise /// bool SelectTranslations(winstd::com_obj& rs) const; /// /// Returns translation data /// /// \param[in] rs Recordset with results /// \param[out] t Translation /// /// \returns /// - true when succeeded /// - false otherwise /// bool GetTranslation(const winstd::com_obj& rs, translation& t) const; /// /// Returns key sequences /// /// \param[out] rs Recordset with results /// /// \returns /// - true when query succeeds /// - false otherwise /// bool SelectKeySequences(winstd::com_obj& rs) const; /// /// Returns key sequence data /// /// \param[in] rs Recordset with results /// \param[out] ks Key sequence /// /// \returns /// - true when succeeded /// - false otherwise /// bool GetKeySequence(const winstd::com_obj& rs, keyseq& ks) const; /// /// Returns languages /// /// \param[out] rs Recordset with results /// /// \returns /// - true when query succeeds /// - false otherwise /// bool SelectLanguages(winstd::com_obj& rs) const; /// /// Returns language data /// /// \param[in] rs Recordset with results /// \param[out] lang Language /// /// \returns /// - true when succeeded /// - false otherwise /// bool GetLanguage(const winstd::com_obj& rs, language& lang) const; /// /// Returns language character /// /// \param[out] rs Recordset with results /// /// \returns /// - true when query succeeds /// - false otherwise /// bool SelectLanguageCharacters(winstd::com_obj& rs) const; /// /// Returns language character data /// /// \param[in] rs Recordset with results /// \param[out] lang Language character data /// /// \returns /// - true when succeeded /// - false otherwise /// bool GetLanguageCharacter(const winstd::com_obj& rs, langchar& lc) const; /// /// Returns character groups /// /// \param[out] rs Recordset with results /// /// \returns /// - true when query succeeds /// - false otherwise /// bool SelectCharacterGroups(winstd::com_obj& rs) const; /// /// Returns character group data /// /// \param[in] rs Recordset with results /// \param[out] cg Character group /// /// \returns /// - true when succeeded /// - false otherwise /// bool GetCharacterGroup(const winstd::com_obj& rs, chrgrp& cg) const; /// /// Returns characters /// /// \param[out] rs Recordset with results /// /// \returns /// - true when query succeeds /// - false otherwise /// bool SelectCharacters(winstd::com_obj& rs) const; /// /// Returns character data /// /// \param[in] rs Recordset with results /// \param[out] chr Character /// /// \returns /// - true when succeeded /// - false otherwise /// bool GetCharacter(const winstd::com_obj& rs, character& chr) const; /// /// Returns character categories /// /// \param[out] rs Recordset with results /// /// \returns /// - true when query succeeds /// - false otherwise /// bool SelectCharacterCategories(winstd::com_obj& rs) const; /// /// Returns character category data /// /// \param[in] rs Recordset with results /// \param[out] cc Character category /// /// \returns /// - true when succeeded /// - false otherwise /// bool GetCharacterCategory(const winstd::com_obj& rs, chrcat& cc) const; /// /// Returns character tags /// /// \param[out] rs Recordset with results /// /// \returns /// - true when query succeeds /// - false otherwise /// bool SelectCharacterTags(winstd::com_obj& rs) const; /// /// Returns character tag data /// /// \param[in] rs Recordset with results /// \param[out] cc Character tag /// /// \returns /// - true when succeeded /// - false otherwise /// bool GetCharacterTag(const winstd::com_obj& rs, chrtag& tc) const; /// /// Returns tag names /// /// \param[out] rs Recordset with results /// /// \returns /// - true when query succeeds /// - false otherwise /// bool SelectTagNames(winstd::com_obj& rs) const; /// /// Returns tag name data /// /// \param[in] rs Recordset with results /// \param[out] tn Tag name /// /// \returns /// - true when succeeded /// - false otherwise /// bool GetTagName(const winstd::com_obj& rs, tagname& tn) const; protected: std::basic_string m_filename; ///< Database filename winstd::com_obj m_db; ///< Database _locale_t m_locale; ///< Database locale winstd::com_obj m_comCharacterGroup; ///< ADO Command for GetCharacterGroup subquery winstd::com_obj m_pCharacterGroup1; ///< \c m_comCharacterGroup parameter }; };