 Issue 29548581:
  Issue 4128, 5138 - Add Parser and Serializer implemented in C++ 
  Base URL: https://github.com/adblockplus/adblockpluscore.git
    
  
    Issue 29548581:
  Issue 4128, 5138 - Add Parser and Serializer implemented in C++ 
  Base URL: https://github.com/adblockplus/adblockpluscore.git
| Left: | ||
| Right: | 
| OLD | NEW | 
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * This file is part of Adblock Plus <https://adblockplus.org/>, | |
| 3 * Copyright (C) 2006-present eyeo GmbH | |
| 4 * | |
| 5 * Adblock Plus is free software: you can redistribute it and/or modify | |
| 6 * it under the terms of the GNU General Public License version 3 as | |
| 7 * published by the Free Software Foundation. | |
| 8 * | |
| 9 * Adblock Plus is distributed in the hope that it will be useful, | |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 * GNU General Public License for more details. | |
| 13 * | |
| 14 * You should have received a copy of the GNU General Public License | |
| 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | |
| 16 */ | |
| 17 | |
| 18 #include "Parser.h" | |
| 19 #include "../subscription/DownloadableSubscription.h" | |
| 20 #include "../subscription/UserDefinedSubscription.h" | |
| 21 #include "../filter/Filter.h" | |
| 22 | |
| 23 namespace | |
| 24 { | |
| 25 bool IsSection(const String& value, const String& expectedSectionName) | |
| 26 { | |
| 27 auto valueLength = value.length(); | |
| 28 // fast check whether it's a section and if its length is expected | |
| 29 if (!(valueLength == expectedSectionName.length() + 2 && value[0] == u'[' && value[valueLength - 1] == u']')) | |
| 30 return false; | |
| 31 OwnedString sectionName(DependentString(value, 1, valueLength - 2)); | |
| 32 sectionName.toLower(); | |
| 33 return sectionName == expectedSectionName; | |
| 34 } | |
| 35 | |
| 36 bool IsSubscriptionSection(const String& value) | |
| 37 { | |
| 38 return IsSection(value, u"subscription"_str); | |
| 39 } | |
| 40 | |
| 41 bool IsSubscriptionFiltersSection(const String& value) | |
| 42 { | |
| 43 return ::IsSection(value, u"subscription filters"_str); | |
| 
Wladimir Palant
2017/12/21 10:30:37
Does :: make sense here? You don't use it above.
 | |
| 44 } | |
| 45 | |
| 46 Subscription::KeyValue CreateKeyValue(const std::pair<DependentString, Depende ntString>& pair) | |
| 47 { | |
| 48 Subscription::KeyValue retValue; | |
| 49 retValue.first = TrimSpaces(pair.first); | |
| 50 retValue.second = TrimSpaces(pair.second); | |
| 51 return retValue; | |
| 52 } | |
| 53 | |
| 54 void DecodeOpeningBracket(DependentString& value) | |
| 55 { | |
| 56 String::size_type skippedChars = 0; | |
| 57 for (String::size_type i = 1; i < value.length(); ++i) | |
| 58 { | |
| 59 if (value[i - 1] == u'\\' && value[i] == u'[') | |
| 60 ++skippedChars; | |
| 61 value[i - skippedChars] = value[i]; | |
| 62 } | |
| 63 if (skippedChars > 0) | |
| 64 value.reset(value, 0, value.length() - skippedChars); | |
| 65 } | |
| 66 } | |
| 67 | |
| 68 Parser::Parser() | |
| 69 : mCurrentState{State::Initial} | |
| 70 { | |
| 71 } | |
| 72 | |
| 73 void Parser::Process(const String& untrimmedLine) | |
| 74 { | |
| 75 auto line = TrimSpaces(untrimmedLine); | |
| 76 // skip empty lines | |
| 77 if (line.length() == 0) | |
| 78 return; | |
| 79 | |
| 80 if (IsSubscriptionSection(line)) | |
| 81 { | |
| 82 Finalize(); | |
| 83 mCurrentState = State::SubscriptionSection; | |
| 84 return; | |
| 85 } | |
| 86 | |
| 87 switch (mCurrentState) | |
| 88 { | |
| 89 case State::Initial: | |
| 90 Initial_processLine(line); | |
| 91 break; | |
| 92 case State::SubscriptionSection: | |
| 93 SubscriptionSection_processLine(line); | |
| 94 break; | |
| 95 case State::SubscriptionFiltersSection: | |
| 96 SubscriptionFiltersSection_processLine(line); | |
| 97 break; | |
| 98 default: | |
| 99 ; | |
| 100 } | |
| 101 } | |
| 102 | |
| 103 void Parser::Finalize() | |
| 104 { | |
| 105 switch (mCurrentState) | |
| 106 { | |
| 107 case State::Initial: | |
| 108 // don't clear file properties because they are also the parser member | |
| 109 break; | |
| 110 case State::SubscriptionSection: | |
| 111 onSubscription(createSubscriptionFromProperties()); | |
| 112 mSubscriptionProperties.clear(); | |
| 113 break; | |
| 114 case State::SubscriptionFiltersSection: | |
| 115 onSubscription(std::move(mSubscription)); | |
| 116 break; | |
| 117 default: | |
| 118 ; | |
| 119 } | |
| 120 } | |
| 121 | |
| 122 Parser::Subscriptions::size_type Parser::GetSubscriptionCount() const | |
| 123 { | |
| 124 return mSubscriptions.size(); | |
| 125 } | |
| 126 | |
| 127 Subscription* Parser::SubscriptionAt(Subscriptions::size_type index) | |
| 128 { | |
| 129 if (index >= mSubscriptions.size()) | |
| 130 return nullptr; | |
| 131 return SubscriptionPtr(mSubscriptions[index]).release(); | |
| 132 } | |
| 133 | |
| 134 SubscriptionPtr Parser::createSubscriptionFromProperties() const | |
| 135 { | |
| 136 return Subscription::FromProperties(mSubscriptionProperties); | |
| 137 } | |
| 138 | |
| 139 void Parser::Initial_processLine(const String& line) | |
| 140 { | |
| 141 // skip # Adblock Plus preferences | |
| 142 if (line[0] == u'#') | |
| 143 return; | |
| 144 | |
| 145 String::size_type assignSignPos = line.find(u'='); | |
| 146 if (assignSignPos != String::npos) | |
| 147 { | |
| 148 mFileProperties.emplace_back(CreateKeyValue(SplitString(line, assignSignPos) )); | |
| 149 return; | |
| 150 } | |
| 151 onFail("Unexpected line value, it should be either a file property or the [Sub scription] section"); | |
| 152 } | |
| 153 | |
| 154 void Parser::SubscriptionSection_processLine(const String& line) | |
| 155 { | |
| 156 String::size_type assignSignPos = line.find(u'='); | |
| 157 if (assignSignPos != String::npos) | |
| 158 { | |
| 159 mSubscriptionProperties.emplace_back(CreateKeyValue(SplitString(line, assign SignPos))); | |
| 160 return; | |
| 161 } | |
| 162 if (IsSubscriptionFiltersSection(line)) | |
| 163 { | |
| 164 mSubscription = createSubscriptionFromProperties(); | |
| 165 mCurrentState = State::SubscriptionFiltersSection; | |
| 166 return; | |
| 167 } | |
| 168 onFail("Unexpected line value, it should be either a subscription property, th e [Subscription filters] section or the [Subscription] section"); | |
| 169 } | |
| 170 | |
| 171 void Parser::SubscriptionFiltersSection_processLine(const String& line) | |
| 172 { | |
| 173 OwnedString lineCopy{line}; | |
| 
Wladimir Palant
2017/12/21 10:30:37
I assume that you create a copy so that DecodeOpen
 | |
| 174 DependentString lineForFilter{lineCopy}; | |
| 175 DecodeOpeningBracket(lineForFilter); | |
| 
Wladimir Palant
2017/12/21 10:30:37
Copying all data around unconditionally seems wast
 | |
| 176 mSubscription->AddFilter(*FilterPtr(Filter::FromText(lineForFilter))); | |
| 177 // any line is considered as a filter, there can be no error | |
| 178 } | |
| 179 | |
| 180 void Parser::onSubscription(SubscriptionPtr subscription) | |
| 181 { | |
| 182 mSubscriptions.emplace_back(std::move(subscription)); | |
| 183 } | |
| OLD | NEW |