void quicksort(int *A, int begin, int end) { int split; if (end - begin <= 1) return; split = get_split(A, begin, end); swap(A, begin, split - 1); assume(split > begin); assume(split <= end); quicksort(A, begin, split - 1); quicksort(A, split, end); }
/** * filter format: * \code{regex} * option = "ocr" | "kbd" | "content" | "regex" | "exact-content" | "exact-regex" * option_separator = "," | "-" * filter * = \s* pattern * | \s* "$:" pattern * | \s* "$" option ( option_separator option )* ":" pattern * \endcode * * With \c conf_regex = KBD_INPUT, exact-content and exact-regex are respectively equivalent to content and regex */ PatternValue get_pattern_value(array_view_const_char const pattern_rule) { using Cat = PatternValue::Cat; struct IsWordSeparator { bool operator == (char c) const { return c == '-' || c == ','; } }; PatternValue pattern_value; constexpr PatternValue empty_pattern_value {}; auto av = array_view_const_char{ ltrim(pattern_rule.begin(), pattern_rule.end()), pattern_rule.end()}; if (not av.empty() && av.front() == '$') { auto end_option_list = std::find(av.begin()+1, av.end(), ':'); if (end_option_list != av.end() && end_option_list+1 != av.end()) { array_view_const_char options(av.begin()+1, end_option_list); bool is_exact = false; for (auto token : get_split(options, IsWordSeparator{})) { auto eq = [](range<char const*> b, array_view_const_char a) { return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin()); }; if (eq(token, cstr_array_view("exact"))) { is_exact = true; } else { if (eq(token, cstr_array_view("ocr"))) { pattern_value.is_ocr = true; if (is_exact) { pattern_value.cat = Cat::is_exact_str; } } else if (eq(token, cstr_array_view("kbd"))) { pattern_value.is_kbd = true; if (is_exact) { pattern_value.cat = Cat::is_exact_str; } } else if (eq(token, cstr_array_view("regex"))) { pattern_value.cat = is_exact ? Cat::is_exact_reg : Cat::is_reg; } else if (eq(token, cstr_array_view("content"))) { pattern_value.cat = is_exact ? Cat::is_exact_str : Cat::is_str; } else { LOG(LOG_WARNING, "Unknown filter option=\"%.*s\" at char %d in \"%.*s\"", int(token.size()), token.begin(), int(token.begin() - pattern_rule.begin()), int(pattern_rule.size()), pattern_rule.begin()); return empty_pattern_value; } is_exact = false; } } if (is_exact) { pattern_value.cat = Cat::is_exact_str; } if (not pattern_value.is_ocr && not pattern_value.is_kbd) { pattern_value.is_ocr = true; } pattern_value.pattern = {end_option_list+1, av.end()}; } } else { pattern_value.pattern = av; pattern_value.is_ocr = true; } return pattern_value; }
AuthorizationChannels::AuthorizationChannels(std::string const & allow, std::string const & deny) { std::vector<CHANNELS::ChannelNameId> allow_ids; std::vector<CHANNELS::ChannelNameId> deny_ids; std::vector<array_view_const_char> allow_large_ids; std::vector<array_view_const_char> deny_large_ids; auto extract = []( array_view_const_char list, std::vector<CHANNELS::ChannelNameId> & ids, std::vector<array_view_const_char> & large_ids ) { bool all = false; for (auto && r : get_split(list.begin(), list.end(), ',')) { auto trimmed = trim(begin(r), end(r)); if (trimmed.empty()) { continue; } if (trimmed[0] == '*') { all = true; } else { switch (trimmed.size()) { case 0: break; case 1: ids.emplace_back(c_array<1>(trimmed.begin())); break; case 2: ids.emplace_back(c_array<2>(trimmed.begin())); break; case 3: ids.emplace_back(c_array<3>(trimmed.begin())); break; case 4: ids.emplace_back(c_array<4>(trimmed.begin())); break; case 5: ids.emplace_back(c_array<5>(trimmed.begin())); break; case 6: ids.emplace_back(c_array<6>(trimmed.begin())); break; case 7: ids.emplace_back(c_array<7>(trimmed.begin())); break; default: large_ids.emplace_back(trimmed.begin(), trimmed.end()); } } } return all; }; this->all_allow_ = extract(allow, allow_ids, allow_large_ids); this->all_deny_ = extract(deny, deny_ids, deny_large_ids); if (this->all_allow_ && !this->all_deny_) { this->rdpdr_restriction_.fill(true); this->cliprdr_restriction_.fill(true); this->rdpsnd_restriction_.fill(true); } auto normalize = [this]( bool set, std::vector<CHANNELS::ChannelNameId> & ids, std::vector<array_view_const_char> & large_ids ) { ::normalize(ids, large_ids, channel_names::cliprdr, set, this->cliprdr_restriction_, cliprde_list()); ::normalize(ids, large_ids, channel_names::rdpdr, set, this->rdpdr_restriction_, rdpdr_list()); ::normalize(ids, large_ids, channel_names::rdpsnd, set, this->rdpsnd_restriction_, rdpsnd_list()); }; normalize(true, allow_ids, allow_large_ids); normalize(false, deny_ids, deny_large_ids); auto normalize_channel = [&](CHANNELS::ChannelNameId channel_name, bool is_allowed) { if (is_allowed) { allow_ids.emplace_back(channel_name); } else { deny_ids.emplace_back(channel_name); } }; normalize_channel( channel_names::cliprdr, cliprdr_up_is_authorized() || cliprdr_down_is_authorized()); bool const is_allowed = ( contains_true(this->rdpdr_restriction_) || contains_true(this->rdpsnd_restriction_)); normalize_channel(channel_names::rdpdr, is_allowed); normalize_channel(channel_names::rdpsnd, is_allowed); auto optimize = [](std::vector<CHANNELS::ChannelNameId> & ids) { auto cmp = [](CHANNELS::ChannelNameId name1, CHANNELS::ChannelNameId name2){ return uint64_t(name1) < uint64_t(name2); }; std::sort(ids.begin(), ids.end(), cmp); ids.erase(std::unique(ids.begin(), ids.end()), ids.end()); }; optimize(allow_ids); optimize(deny_ids); this->allow_and_deny_.reserve(allow_ids.size() + deny_ids.size()); this->allow_and_deny_.insert(this->allow_and_deny_.end(), allow_ids.begin(), allow_ids.end()); this->allow_and_deny_.insert(this->allow_and_deny_.end(), deny_ids.begin(), deny_ids.end()); this->allow_and_deny_pivot_ = this->allow_and_deny_.data() + allow_ids.size(); }