/** Look ahead function to test whether a dictionary matches a condition */ t_bool _dict_recurse_match_dict(t_dict_recurse *x, t_dictionary *dict, t_symbol **key_match, t_symbol **value_match) { TRACE("_dict_recurse_match_dict"); // Get the dictionary keys long key_cnt = 0; t_symbol **key_arr = NULL; t_symbol *key = gensym(""); t_atom value[1]; *key_match = gensym(""); *value_match = gensym(""); dictionary_getkeys(dict, &key_cnt, &key_arr); t_bool test = false; for (t_int32 ind = 0; ind < key_cnt; ind++) { key = key_arr[ind]; if (!regexpr_match(x->search_key_expr, key)) { continue; } dictionary_getatom(dict, key, value); if (regexpr_match(x->search_val_expr, atom_getsym(value))) { test = true; *key_match = key; *value_match = atom_getsym(value); break; } } if (key_arr) { dictionary_freekeys(dict, key_cnt, key_arr); } return test; }
void dict_recurse_test_match(t_dict_recurse *x, t_symbol *sym, long argc, t_atom *argv) { t_symbol *expr = atom_getsym(argv); t_symbol *key_sym = atom_getsym(argv + 1); regexpr_set(x->search_key_expr, expr); regexpr_match(x->search_key_expr, key_sym); regexpr_reset(x->search_key_expr); }
void FilterList::convert(const std::vector<std::string> & ruleList, const std::set<std::string> & disabled_list, std::vector<RegExpFilter *> & regexpList, std::vector<ElemHideSelector *> & elemHideFilter) { static const char * ELEMHIDE_PATTERN = "^([^\\/\\*\\|\\@\"]*?)#(?:([\\w\\-]+|\\*)((?:\\([\\w\\-]+(?:[$^*]?=[^\\(\\)\"]*)?\\))*)|#([^{}]+))$"; static const char * REGEXPR_PATTERN = "^\\/(.*)\\/$"; static const char * OPTIONS_PATTERN = "\\$(~?[\\w\\-]+(?:=[^,\\s]+)?(?:,~?[\\w\\-]+(?:=[^,\\s]+)?)*)$"; for ( auto iter = ruleList.begin(); iter != ruleList.end(); iter++ ) { std::string rule( * iter ); if ( disabled_list.find(rule) != disabled_list.end() ) { // 被禁用的规则,不做任何处理 continue; } auto pos = knownFilters.find(rule); if ( pos != knownFilters.end() ) { Filter * p = pos->second; if ( p ) { RegExpFilter * regexpFilter = dynamic_cast<RegExpFilter *>(p); if ( regexpFilter ) { regexpList.push_back(regexpFilter); // 加引用计数, 以免被释放 regexpFilter->AddRef(); } else { ElemHideSelector * selector = dynamic_cast<ElemHideSelector *>(p); if ( selector ) { elemHideFilter.push_back(selector); // 加引用计数, 以免被释放 selector->AddRef(); } else { // 不应该走到这里, 但是如果真到这里了, 把 p 从 map 里面去掉 knownFilters.erase(pos); p->Release(); } } continue; } } // 元素隐藏规则 std::string results[4]; if ( regexpr_match(ELEMHIDE_PATTERN, rule.c_str(), FALSE, results, 4) ) { const std::string & domain = results[0]; const std::string & tagName = results[1]; const std::string & attrRules = results[2]; const std::string & selector = results[3]; if ( ElemHideSelector * filter = ElemHideSelector::fromText(domain, tagName, attrRules, selector) ) { elemHideFilter.push_back(filter); knownFilters[rule] = filter; } } else { std::string re_rule(rule); // 访问过滤规则 std::string options_str; if ( regexpr_match(OPTIONS_PATTERN, re_rule.c_str(), FALSE, &options_str, 1) ) { // 把参数部分去掉 regexpr_replace(OPTIONS_PATTERN, re_rule.c_str(), "", re_rule); } if ( regexpr_match(REGEXPR_PATTERN, re_rule.c_str(), FALSE, results, 1) ) { re_rule = results[0]; } else { // 将 adblockplus 规则转换成正则表达式规则 regexpr_replace("\\*+", re_rule.c_str(), "*", re_rule, TRUE); regexpr_replace("\\^\\|$", re_rule.c_str(), "^", re_rule, FALSE); regexpr_replace("(\\W)", re_rule.c_str(), "\r\\1", re_rule, TRUE); string_replace(re_rule, "\r", "\\"); regexpr_replace("\\\\\\*", re_rule.c_str(), ".*", re_rule, TRUE); regexpr_replace("\\\\\\^", re_rule.c_str(), "(?:[^\rw\r-.%\ru0080-\ruFFFF]|$)", re_rule, TRUE); regexpr_replace("^\\\\\\|\\\\\\|", re_rule.c_str(), "^[\rw\r-]+:\r/+(?!\r/)(?:[^\r/]+\r.)?", re_rule, FALSE); string_replace(re_rule, "\r", "\\"); regexpr_replace("^\\\\\\|", re_rule.c_str(), "^", re_rule, FALSE); regexpr_replace("\\\\\\|$", re_rule.c_str(), "$", re_rule, FALSE); regexpr_replace("^(\\.\\*)", re_rule.c_str(), "", re_rule, FALSE); regexpr_replace("(\\.\\*)$", re_rule.c_str(), "", re_rule, FALSE); } if ( RegExpFilter * filter = RegExpFilter::fromText(re_rule, options_str) ) { regexpList.push_back(filter); knownFilters[rule] = filter; } } } }
/** Called by _dict_recurse_dict() for each entry and _dict_recurse_array() for each index */ t_int32 _dict_recurse_value(t_dict_recurse *x, t_atom *value, t_int32 depth) { TRACE("_dict_recurse_value"); long type = atom_gettype(value); // ==== INT ==== if (type == A_LONG) { snprintf_zero(x->str_tmp, MAX_LEN_NUMBER, "%i", atom_getlong(value)); _dict_recurse_value_find(x, value, x->str_tmp); } // ==== FLOAT ==== else if (type == A_FLOAT) { snprintf_zero(x->str_tmp, MAX_LEN_NUMBER, "%i", atom_getfloat(value)); _dict_recurse_value_find(x, value, x->str_tmp); } // ==== SYMBOL / STRING ==== // NB: values in arrays are not A_SYM but A_OBJ else if ((type == A_SYM) || atomisstring(value)) { t_symbol *value_sym = atom_getsym(value); switch (x->command) { // == FIND A SYMBOL VALUE case CMD_FIND_VALUE_SYM: if (regexpr_match(x->search_val_expr, value_sym)) { POST(" %s \"%s\"", x->path, value_sym->s_name); x->count++; } break; // == FIND AN ENTRY case CMD_FIND_ENTRY: if (regexpr_match(x->search_key_expr, x->key_iter) && regexpr_match(x->search_val_expr, value_sym) && (x->type_iter == VALUE_TYPE_DICT)) { POST(" %s \"%s\"", x->path, value_sym->s_name); x->count++; } break; // == REPLACE A SYMBOL VALUE case CMD_REPLACE_VALUE_SYM: if (regexpr_match(x->search_val_expr, value_sym)) { // If the value is from a dictionary entry if (x->type_iter == VALUE_TYPE_DICT) { dictionary_chuckentry(x->dict_iter, x->key_iter); dictionary_appendsym(x->dict_iter, x->key_iter, x->replace_val_sym); } // If the value is from an array else if (x->type_iter == VALUE_TYPE_ARRAY) { atom_setsym(value, x->replace_val_sym); } x->count++; if (x->a_verbose) { POST(" %s \"%s\" replaced by \"%s\"", x->path, value_sym->s_name, x->replace_val_sym->s_name); } } break; // == REPLACE AN ENTRY case CMD_REPLACE_ENTRY: if (regexpr_match(x->search_key_expr, x->key_iter) && regexpr_match(x->search_val_expr, value_sym) && (x->type_iter == VALUE_TYPE_DICT)) { dictionary_chuckentry(x->dict_iter, x->key_iter); dictionary_appendsym(x->dict_iter, x->replace_key_sym, x->replace_val_sym); x->count++; if (x->a_verbose) { POST(" %s \"%s\" replaced by (%s : %s)", x->path, value_sym->s_name, x->replace_key_sym->s_name, x->replace_val_sym->s_name); } } break; // == DELETE A SYMBOL VALUE case CMD_DELETE_VALUE_SYM: if (regexpr_match(x->search_val_expr, value_sym)) { // If the value is from a dictionary entry if (x->type_iter == VALUE_TYPE_DICT) { dictionary_deleteentry(x->dict_iter, x->key_iter); } // If the value is from an array else if (x->type_iter == VALUE_TYPE_ARRAY) { atomarray_chuckindex(x->array_iter, x->index_iter); } x->count++; if (x->a_verbose) { POST(" %s \"%s\" deleted", x->path, value_sym->s_name); } return VALUE_DEL; } break; // == DELETE A SYMBOL VALUE case CMD_DELETE_ENTRY: if (regexpr_match(x->search_key_expr, x->key_iter) && regexpr_match(x->search_val_expr, value_sym) && (x->type_iter == VALUE_TYPE_DICT)) { dictionary_deleteentry(x->dict_iter, x->key_iter); x->count++; if (x->a_verbose) { POST(" %s \"%s\" deleted", x->path, value_sym->s_name); } return VALUE_DEL; } break; // == DEFAULT: CMD_FIND_KEY or CMD_FIND_KEY_IN default: snprintf_zero(x->str_tmp, MAX_LEN_NUMBER, "\"%s\"", atom_getsym(value)->s_name); _dict_recurse_value_find(x, value, x->str_tmp); break; } } // ==== DICTIONARY ==== else if (atomisdictionary(value)) { t_dictionary *sub_dict = (t_dictionary *)atom_getobj(value); t_symbol *key_match = gensym(""); t_symbol *value_match = gensym(""); switch (x->command) { case CMD_FIND_DICT_CONT_ENTRY: if (_dict_recurse_match_dict(x, sub_dict, &key_match, &value_match)) { x->count++; POST(" %s: dict containing (%s : %s)", x->path, key_match->s_name, value_match->s_name); } break; case CMD_REPLACE_DICT_CONT_ENTRY: if (_dict_recurse_match_dict(x, sub_dict, &key_match, &value_match)) { t_dictionary *dict_cpy = dictionary_new(); dictionary_clone_to_existing(x->replace_dict, dict_cpy); // If the value is from a dictionary entry if (x->type_iter == VALUE_TYPE_DICT) { dictionary_deleteentry(x->dict_iter, x->key_iter); dictionary_appenddictionary(x->dict_iter, x->key_iter, (t_object *)dict_cpy); } // If the value is from an array else if (x->type_iter == VALUE_TYPE_ARRAY) { long array_len; t_atom *atom_arr; atomarray_getatoms(x->array_iter, &array_len, &atom_arr); atom_setobj(atom_arr + x->index_iter, dict_cpy); } x->count++; if (x->a_verbose) { POST(" %s: dict containing (%s : %s): replaced by \"%s\"", x->path, key_match->s_name, value_match->s_name, x->replace_dict_sym->s_name); } return VALUE_NO_DEL; } break; case CMD_DELETE_DICT_CONT_ENTRY: if (_dict_recurse_match_dict(x, sub_dict, &key_match, &value_match)) { // If the value is from a dictionary entry if (x->type_iter == VALUE_TYPE_DICT) { dictionary_deleteentry(x->dict_iter, x->key_iter); } // If the value is from an array else if (x->type_iter == VALUE_TYPE_ARRAY) { atomarray_chuckindex(x->array_iter, x->index_iter); object_free(sub_dict); } x->count++; if (x->a_verbose) { POST(" %s: dict containing (%s : %s): deleted", x->path, key_match->s_name, value_match->s_name); } return VALUE_DEL; } break; case CMD_APPEND_IN_DICT_CONT_ENTRY: if (_dict_recurse_match_dict(x, sub_dict, &key_match, &value_match)) { dictionary_appendsym(sub_dict, x->replace_key_sym, x->replace_val_sym); x->count++; if (x->a_verbose) { POST(" %s: dict containing (%s : %s): appended (%s : %s)", x->path, key_match->s_name, value_match->s_name, x->replace_key_sym->s_name, x->replace_val_sym->s_name); } } break; case CMD_APPEND_IN_DICT_CONT_ENTRY_D: if (_dict_recurse_match_dict(x, sub_dict, &key_match, &value_match) && dictionary_hasentry(x->replace_dict, x->replace_key_sym)) { t_symbol *key[2]; key[0] = x->replace_key_sym; key[1] = NULL; dictionary_copyentries(x->replace_dict, sub_dict, key); // NB: Strange it does not require the array size x->count++; if (x->a_verbose) { POST(" %s: dict containing (%s : %s): appended entry (%s : ...) from \"%s\"", x->path, key_match->s_name, value_match->s_name, x->replace_key_sym->s_name, x->replace_dict_sym->s_name); } } break; case CMD_APPEND_IN_DICT_FROM_KEY: if (regexpr_match(x->search_key_expr, x->key_iter) && (x->type_iter == VALUE_TYPE_DICT) && dictionary_hasentry(x->replace_dict, x->replace_key_sym)) { t_symbol *key[2]; key[0] = x->replace_key_sym; key[1] = NULL; dictionary_copyentries(x->replace_dict, sub_dict, key); // NB: Strange it does not require the array size x->count++; if (x->a_verbose) { POST(" %s: dict value: appended entry (%s : ...) from \"%s\"", x->path, x->replace_key_sym->s_name, x->replace_dict_sym->s_name); } } break; default: _dict_recurse_value_find(x, value, "_DICT_"); } // End of command "switch ..." _dict_recurse_dict(x, sub_dict, depth); } // End of dictionary "else if ..." // ==== ARRAY ==== else if (atomisatomarray(value)) { _dict_recurse_value_find(x, value, "_ARRAY_"); t_atomarray *atomarray = (t_atomarray *)atom_getobj(value); _dict_recurse_array(x, atomarray, depth); } return VALUE_NO_DEL; }
void _dict_recurse_dict(t_dict_recurse *x, t_dictionary *dict, t_int32 depth) { TRACE("_dict_recurse_dict"); t_atom atom[1]; // ==== Store the state variables on the beginning of the function t_bool has_match_ini = x->has_match; t_int32 path_len_ini = (t_int32)strlen(x->path); t_value_type type_iter_ini = x->type_iter; t_dictionary *dict_iter_ini = x->dict_iter; t_symbol *key_iter_ini = x->key_iter; // ==== Add :: to the path strncat_zero(x->path, "::", x->path_len_max); // ==== Get the dictionary keys long key_cnt = 0; t_symbol **key_arr = NULL; dictionary_getkeys(dict, &key_cnt, &key_arr); // ==== Increment the depth depth++; // ==== Set the trailing variables before for the recursions x->type_iter = VALUE_TYPE_DICT; x->dict_iter = dict; // ==== Loop through the keys for (t_int32 ind = 0; ind < key_cnt; ind++) { x->key_iter = key_arr[ind]; // == Opening actions depending on which command is being processed switch (x->command) { case CMD_FIND_KEY_IN: case CMD_FIND_KEY: if (regexpr_match(x->search_key_expr, x->key_iter)) { x->has_match = true; x->count++; } // x->has_match changed break; case CMD_REPLACE_KEY: if (regexpr_match(x->search_key_expr, x->key_iter)) { dictionary_getatom(dict, x->key_iter, atom); dictionary_chuckentry(dict, x->key_iter); dictionary_appendatom(dict, x->replace_key_sym, atom); x->count++; if (x->a_verbose == true) { POST(" %s%s replaced by \"%s\"", x->path, x->key_iter->s_name, x->replace_key_sym->s_name); } x->key_iter = x->replace_key_sym; } break; case CMD_DELETE_KEY: if (regexpr_match(x->search_key_expr, x->key_iter)) { dictionary_deleteentry(dict, x->key_iter); x->count++; if (x->a_verbose == true) { POST(" %s%s deleted", x->path, x->key_iter->s_name, x->replace_key_sym->s_name); } continue; } // NB: No further recursion break; case CMD_REPLACE_VALUE_FROM_DICT: if (regexpr_match(x->search_key_expr, x->key_iter) && dictionary_hasentry(x->replace_dict, x->key_iter)) { t_symbol *key_iter[2]; key_iter[0] = x->key_iter; key_iter[1] = NULL; dictionary_copyentries(x->replace_dict, dict, key_iter); // NB: Strange it does not require the array size x->count++; if (x->a_verbose == true) { POST(" %s%s replaced from \"%s\"", x->path, x->key_iter->s_name, x->replace_dict_sym->s_name); } continue; } // NB: No further recursion break; default: break; } // >>>> END switch through potential commands // == Set the trailing variables before for the recursion strncat_zero(x->path, x->key_iter->s_name, x->path_len_max); // NB: x->path changed // == Get the value and recurse to it dictionary_getatom(dict, x->key_iter, atom); // NB: This creates a copy _dict_recurse_value(x, atom, depth); // == Reset the values that changed in this loop x->path[path_len_ini + 2] = '\0'; x->has_match = has_match_ini; } // >>>> END of loop through the keys // ==== Restore the remaining state variables to their beginning values x->type_iter = type_iter_ini; x->dict_iter = dict_iter_ini; x->key_iter = key_iter_ini; if (key_arr) { dictionary_freekeys(dict, key_cnt, key_arr); } }