void INIParser::process(const wstring& line, bool eof) { static const RegExp re1 = L"/^(\\w+)=(.*)$/"; static const RegExp re2 = L"/^\\s*\\[(.+)\\]\\s*$/"; static const RegExp re3 = L"/\\\\\\[/g"; static const wstring strDisabled = L"disabled"; static const wstring strTrue = L"true"; static const wstring strLeftBracket = L"["; RegExpMatch* match = NULL; if (wantObj && (match = re1.exec(line))) { curObj[match->substrings[1]] = match->substrings[2]; delete match; } else if (eof || (match = re2.exec(line))) { wstring strSection; if (match) { strSection = toLowerCase(match->substrings[1]); delete match; } if (wantObj ? curObj.size() : curList.size()) { // Process current object before going to next section switch (curSection) { case FILTER: case PATTERN: // create the filter, with certain properties set up // do not insert it into the filters set // if it's active, it'll be inserted in some subscription we'll later parse persistedFilters.insert(Filter::fromObject(curObj)); break; case SUBSCRIPTION: // not supported, just record whether the whole subscription is disabled or not { auto iter = curObj.find(strDisabled); subscriptionDisabled = iter != curObj.end() && iter->second == strTrue; } break; case SUBSCRIPTION_FILTERS: case SUBSCRIPTION_PATTERNS: case USER_PATTERNS: if (!subscriptionDisabled) { for (size_t i = 0; i < curList.size(); i++) { const wstring& text = curList[i]; Filter* filter = Filter::fromText(text); // need to reset the disabled property since we don't clear // the global filter list between reloads ActiveFilter* activeFilter = filter->toActiveFilter(); if (activeFilter) { // Only reset disabled property for those not persisted yet if (persistedFilters.find(filter) == persistedFilters.end()) activeFilter->setDisabled(false); // just put the filter in INIParser::filters filters.insert(activeFilter); } } } } } if (eof) return; auto iter = sectionMapper.find(strSection); if (iter != sectionMapper.end()) { curSection = iter->second; switch (curSection) { case FILTER: case PATTERN: case SUBSCRIPTION: wantObj = true; curObj.clear(); break; case SUBSCRIPTION_FILTERS: case SUBSCRIPTION_PATTERNS: case USER_PATTERNS: default: wantObj = false; curList.clear(); } } } else if (!wantObj && line.length()) { curList.push_back(replace(line, re3, strLeftBracket)); } }
unsigned int AdBlockPlus::asyncLoader(void* ppathname) { wstring* pstr = reinterpret_cast<wstring*>(ppathname); wstring pathname = *pstr; delete pstr; bool loaded = false; // then load stuff CFile file; if (file.Open(pathname.c_str(), CFile::modeRead | CFile::shareDenyWrite)) { wstring content; bool success = Utils::File::readFile(file, content); file.Close(); if (success) { WriterLock wl(s_mutex); clearFiltersInternal(true); INIParser parser; // split content into lines, process with INIParser one by one size_t lastPos = 0; wchar_t lastCh = 0; for (size_t i = 0; i < content.length(); i++) { wchar_t ch = content[i]; // accept CR, LF and CRLF sequence if (ch == L'\r' || (ch == L'\n' && lastCh != L'\r')) { parser.process(content.substr(lastPos, i - lastPos), false); } if (ch == L'\r' || ch == L'\n') lastPos = i + 1; lastCh = ch; } if (lastPos < content.length()) parser.process(content.substr(lastPos, content.length() - lastPos), false); parser.process(L"", true); // put everything in INIParser::filters into the matcher for (auto iter = parser.filters.begin(); iter != parser.filters.end(); ++iter) { ActiveFilter* filter = *iter; if (!filter || filter->isDisabled()) continue; RegExpFilter* regexpFilter = filter->toRegExpFilter(); if (regexpFilter) { regexpMatcher.add(regexpFilter); continue; } ElemHideFilter* elemhideFilter = filter->toElemHideFilter(); if (elemhideFilter) elemhideMatcher.add(elemhideFilter); } // generate the general filter list for elemhideMatcher to improve speed elemhideMatcher.generateGeneralFilters(); loaded = true; } } // Notify main thread about load completion CIEHostWindow* pWindow = CIEHostWindow::GetAnyUtilsWindow(); if (pWindow) pWindow->RunAsync([=] { filterLoadedCallback(loaded); pWindow->SendMessage(UserMessage::WM_USER_MESSAGE, loaded ? UserMessage::WPARAM_ABP_FILTER_LOADED : UserMessage::WPARAM_ABP_LOAD_FAILURE, 0); }); else filterLoadedCallback(loaded); return 0; }
unsigned int AdBlockPlus::asyncLoader(void* vpparam) { AsyncLoaderParam* pparam = reinterpret_cast<AsyncLoaderParam*>(vpparam); wstring pathname = std::move(pparam->pathname); wstring additionalFilters = std::move(pparam->additionalFilters); unordered_map<wstring, wstring> options = std::move(pparam->options); delete pparam; bool loaded = false; // then load stuff CFile file; if (file.Open(pathname.c_str(), CFile::modeRead | CFile::shareDenyWrite)) { wstring content; bool success = Utils::File::readFile(file, content); file.Close(); if (success) { WriterLock wl(s_mutex); clearFiltersInternal(true); INIParser parser(options); loadContent(parser, content); loadContent(parser, additionalFilters); // put everything in INIParser::filters into the matcher for (auto iter = parser.filters.begin(); iter != parser.filters.end(); ++iter) { ActiveFilter* filter = *iter; if (!filter || filter->isDisabled()) continue; RegExpFilter* regexpFilter = filter->toRegExpFilter(); if (regexpFilter) { regexpMatcher.add(regexpFilter); continue; } ElemHideFilter* elemhideFilter = filter->toElemHideFilter(); if (elemhideFilter) elemhideMatcher.add(elemhideFilter); } // generate the general filter list for elemhideMatcher to improve speed elemhideMatcher.generateGeneralFilters(); loaded = true; } } // Notify main thread about load completion CIEHostWindow* pWindow = CIEHostWindow::GetAnyUtilsWindow(); if (pWindow) { pWindow->RunAsync([=] { // filterLoadedCallback() should be called on the main thread // to ensure atomicity; // Must call the callback before sending the message filterLoadedCallback(loaded); pWindow->SendMessage(UserMessage::WM_USER_MESSAGE, loaded ? UserMessage::WPARAM_ABP_FILTER_LOADED : UserMessage::WPARAM_ABP_LOAD_FAILURE, 0); }); } else { // Just a fallback, may never get to here filterLoadedCallback(loaded); } return 0; }