1 /* 2 * SPDX-FileCopyrightText: 2015-2017 CSSlayer <wengxt@gmail.com> 3 * 4 * SPDX-License-Identifier: LGPL-2.1-or-later 5 */ 6 7 #ifndef _FCITX_LIBIME_TABLE_TABLERULE_H_ 8 #define _FCITX_LIBIME_TABLE_TABLERULE_H_ 9 10 #include "libimetable_export.h" 11 12 #include <boost/algorithm/string.hpp> 13 #include <cstdint> 14 #include <iostream> 15 #include <libime/core/utils.h> 16 #include <sstream> 17 #include <stdexcept> 18 #include <string> 19 #include <string_view> 20 #include <vector> 21 22 namespace libime { 23 enum class TableRuleEntryFlag : std::uint32_t { FromFront, FromBack }; 24 25 enum class TableRuleFlag : std::uint32_t { LengthLongerThan, LengthEqual }; 26 27 class LIBIMETABLE_EXPORT TableRuleEntry { 28 public: 29 TableRuleEntry(TableRuleEntryFlag _flag = TableRuleEntryFlag::FromFront, 30 uint8_t _character = 0, uint8_t _encodingIndex = 0) flag_(_flag)31 : flag_(_flag), character_(_character), encodingIndex_(_encodingIndex) { 32 } 33 TableRuleEntry(std::istream & in)34 explicit TableRuleEntry(std::istream &in) { 35 throw_if_io_fail(unmarshall(in, flag_)); 36 throw_if_io_fail(unmarshall(in, character_)); 37 throw_if_io_fail(unmarshall(in, encodingIndex_)); 38 } 39 40 FCITX_INLINE_DEFINE_DEFAULT_DTOR_COPY_AND_MOVE(TableRuleEntry); 41 42 friend std::ostream &operator<<(std::ostream &out, 43 const TableRuleEntry &r) { 44 marshall(out, r.flag_) && marshall(out, r.character_) && 45 marshall(out, r.encodingIndex_); 46 return out; 47 } 48 isPlaceHolder()49 bool isPlaceHolder() const { 50 return character_ == 0 || encodingIndex_ == 0; 51 } 52 flag()53 TableRuleEntryFlag flag() const { return flag_; } character()54 uint8_t character() const { return character_; } encodingIndex()55 uint8_t encodingIndex() const { return encodingIndex_; } 56 57 private: 58 TableRuleEntryFlag flag_; 59 uint8_t character_; 60 uint8_t encodingIndex_; 61 }; 62 63 class TableRule { 64 public: TableRule(const std::string & ruleString,unsigned int maxLength)65 TableRule(const std::string &ruleString, unsigned int maxLength) { 66 if (!ruleString[0]) { 67 throw std::invalid_argument("invalid rule string"); 68 } 69 70 switch (ruleString[0]) { 71 case 'e': 72 case 'E': 73 flag_ = TableRuleFlag::LengthEqual; 74 break; 75 76 case 'a': 77 case 'A': 78 flag_ = TableRuleFlag::LengthLongerThan; 79 break; 80 81 default: 82 throw std::invalid_argument("invalid rule string"); 83 } 84 85 auto equalSignPos = ruleString.find('=', 1); 86 if (equalSignPos == std::string::npos) { 87 throw std::invalid_argument("invalid rule string"); 88 } 89 90 auto afterEqualSign = 91 std::string_view(ruleString).substr(equalSignPos + 1); 92 std::vector<std::string> entryStrings; 93 boost::split(entryStrings, afterEqualSign, boost::is_any_of("+")); 94 if (entryStrings.empty() || entryStrings.size() > maxLength) { 95 throw std::invalid_argument("invalid rule string"); 96 } 97 98 auto beforeEqualSign = 99 std::string_view(ruleString).substr(0, equalSignPos); 100 if (beforeEqualSign.size() != 2 || !isdigit(beforeEqualSign[1])) { 101 throw std::invalid_argument("invalid rule string"); 102 } 103 104 phraseLength_ = beforeEqualSign[1] - '0'; 105 if (phraseLength_ <= 0 || phraseLength_ > maxLength) { 106 throw std::invalid_argument("Invalid phrase length"); 107 } 108 109 unsigned int idx = 0; 110 for (const auto &entryString : entryStrings) { 111 idx++; 112 TableRuleEntryFlag entryFlag; 113 switch (entryString[0]) { 114 case 'p': 115 case 'P': 116 entryFlag = TableRuleEntryFlag::FromFront; 117 break; 118 case 'n': 119 case 'N': 120 entryFlag = TableRuleEntryFlag::FromBack; 121 break; 122 default: 123 throw std::invalid_argument("invalid rule entry flag"); 124 } 125 126 if (entryString.size() != 3 || !isdigit(entryString[1]) || 127 !isdigit(entryString[2])) { 128 throw std::invalid_argument("invalid rule entry"); 129 } 130 131 int8_t character = entryString[1] - '0'; // 0 ~ maxLength 132 int8_t encodingIndex = entryString[2] - '0'; // 0 ~ maxLength 133 if (character < 0 || character > static_cast<int>(maxLength) || 134 encodingIndex < 0 || 135 encodingIndex > static_cast<int>(maxLength) || 136 ((character == 0) ^ (encodingIndex == 0))) { 137 throw std::invalid_argument("invalid rule entry"); 138 } 139 140 entries_.push_back( 141 TableRuleEntry(entryFlag, character, encodingIndex)); 142 } 143 } 144 145 TableRule(TableRuleFlag _flag = TableRuleFlag::LengthEqual, 146 int _phraseLength = 0, std::vector<TableRuleEntry> _entries = {}) flag_(_flag)147 : flag_(_flag), phraseLength_(_phraseLength), 148 entries_(std::move(_entries)) {} 149 TableRule(std::istream & in)150 explicit TableRule(std::istream &in) { 151 uint32_t size; 152 throw_if_io_fail(unmarshall(in, flag_)); 153 throw_if_io_fail(unmarshall(in, phraseLength_)); 154 throw_if_io_fail(unmarshall(in, size)); 155 entries_.reserve(size); 156 for (auto i = 0U; i < size; i++) { 157 entries_.emplace_back(in); 158 } 159 } 160 161 FCITX_INLINE_DEFINE_DEFAULT_DTOR_COPY_AND_MOVE(TableRule) 162 163 friend std::ostream &operator<<(std::ostream &out, const TableRule &r) { 164 if (marshall(out, r.flag_) && marshall(out, r.phraseLength_) && 165 marshall(out, static_cast<uint32_t>(r.entries_.size()))) { 166 for (const auto &entry : r.entries_) { 167 if (!(out << entry)) { 168 break; 169 } 170 } 171 } 172 return out; 173 } 174 name()175 std::string name() const { 176 std::string result; 177 result += ((flag_ == TableRuleFlag::LengthEqual) ? 'e' : 'a'); 178 result += std::to_string(phraseLength_); 179 180 return result; 181 } 182 toString()183 std::string toString() const { 184 std::string result; 185 186 result += name(); 187 result += '='; 188 bool first = true; 189 for (const auto &entry : entries_) { 190 if (first) { 191 first = false; 192 } else { 193 result += '+'; 194 } 195 result += 196 ((entry.flag() == TableRuleEntryFlag::FromFront) ? 'p' : 'n'); 197 result += static_cast<char>('0' + entry.character()); 198 result += static_cast<char>('0' + entry.encodingIndex()); 199 } 200 return result; 201 } 202 flag()203 TableRuleFlag flag() const { return flag_; } phraseLength()204 uint8_t phraseLength() const { return phraseLength_; } entries()205 const std::vector<TableRuleEntry> &entries() const { return entries_; } codeLength()206 size_t codeLength() const { 207 size_t sum = 0; 208 for (const auto &entry : entries_) { 209 if (entry.isPlaceHolder()) { 210 continue; 211 } 212 sum += 1; 213 } 214 return sum; 215 } 216 217 private: 218 TableRuleFlag flag_ = TableRuleFlag::LengthLongerThan; 219 uint8_t phraseLength_ = 0; 220 std::vector<TableRuleEntry> entries_; 221 }; 222 } // namespace libime 223 224 #endif // _FCITX_LIBIME_TABLE_TABLERULE_H_ 225