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 package org.adblockplus.sbrowser.contentblocker.engine; |
| 19 |
| 20 import java.io.IOException; |
| 21 import java.io.InputStream; |
| 22 import java.net.URL; |
| 23 import java.util.ArrayList; |
| 24 import java.util.HashMap; |
| 25 import java.util.LinkedList; |
| 26 import java.util.List; |
| 27 |
| 28 import javax.xml.parsers.ParserConfigurationException; |
| 29 import javax.xml.parsers.SAXParser; |
| 30 import javax.xml.parsers.SAXParserFactory; |
| 31 |
| 32 import org.xml.sax.Attributes; |
| 33 import org.xml.sax.SAXException; |
| 34 import org.xml.sax.helpers.DefaultHandler; |
| 35 |
| 36 final class DefaultSubscriptions |
| 37 { |
| 38 private final List<DefaultSubscriptionInfo> subscriptions = new ArrayList<>(); |
| 39 private final List<DefaultSubscriptionInfo> linearSubscriptions = new ArrayLis
t<>(); |
| 40 private final HashMap<String, DefaultSubscriptionInfo> urlMap = new HashMap<>(
); |
| 41 private final List<DefaultSubscriptionInfo> adsSubscriptions = new ArrayList<>
(); |
| 42 private final List<DefaultSubscriptionInfo> otherSubscriptions = new ArrayList
<>(); |
| 43 |
| 44 private DefaultSubscriptions initialize() |
| 45 { |
| 46 this.listSubscriptions(this.linearSubscriptions); |
| 47 |
| 48 for (final DefaultSubscriptionInfo s : this.linearSubscriptions) |
| 49 { |
| 50 final String url = s.getUrl(); |
| 51 final String type = s.getType(); |
| 52 |
| 53 if (url.length() > 0) |
| 54 { |
| 55 this.urlMap.put(url, s); |
| 56 } |
| 57 |
| 58 if (type.length() == 0 || type.equals("ads")) |
| 59 { |
| 60 this.adsSubscriptions.add(s); |
| 61 } |
| 62 else if (type.equals("other")) |
| 63 { |
| 64 this.otherSubscriptions.add(s); |
| 65 } |
| 66 } |
| 67 |
| 68 return this; |
| 69 } |
| 70 |
| 71 public List<Subscription> createSubscriptions() throws IOException |
| 72 { |
| 73 final ArrayList<Subscription> subs = new ArrayList<>(); |
| 74 for (DefaultSubscriptionInfo info : this.linearSubscriptions) |
| 75 { |
| 76 if (!info.getUrl().isEmpty()) |
| 77 { |
| 78 final Subscription sub = Subscription.create(info.getUrl()); |
| 79 sub.putMeta(Subscription.KEY_TITLE, info.getTitle()); |
| 80 subs.add(sub); |
| 81 } |
| 82 } |
| 83 return subs; |
| 84 } |
| 85 |
| 86 public DefaultSubscriptionInfo getForUrl(final String url) |
| 87 { |
| 88 return this.urlMap.get(url); |
| 89 } |
| 90 |
| 91 public DefaultSubscriptionInfo getForUrl(final URL url) |
| 92 { |
| 93 return url != null ? this.getForUrl(url.toString()) : null; |
| 94 } |
| 95 |
| 96 public List<DefaultSubscriptionInfo> getAdsSubscriptions() |
| 97 { |
| 98 return adsSubscriptions; |
| 99 } |
| 100 |
| 101 private void listSubscriptions(final List<DefaultSubscriptionInfo> output) |
| 102 { |
| 103 for (final DefaultSubscriptionInfo s : this.subscriptions) |
| 104 { |
| 105 this.listSubscriptions(s, output); |
| 106 } |
| 107 } |
| 108 |
| 109 private void listSubscriptions(final DefaultSubscriptionInfo parent, |
| 110 final List<DefaultSubscriptionInfo> output) |
| 111 { |
| 112 output.add(parent); |
| 113 for (final DefaultSubscriptionInfo s : parent.variants) |
| 114 { |
| 115 this.listSubscriptions(s, output); |
| 116 } |
| 117 for (final DefaultSubscriptionInfo s : parent.supplements) |
| 118 { |
| 119 this.listSubscriptions(s, output); |
| 120 } |
| 121 } |
| 122 |
| 123 public static DefaultSubscriptions fromStream(final InputStream in) throws IOE
xception |
| 124 { |
| 125 try |
| 126 { |
| 127 final SAXParserFactory factory = SAXParserFactory.newInstance(); |
| 128 factory.setValidating(false); |
| 129 final SAXParser parser = factory.newSAXParser(); |
| 130 final SubscriptionParser handler = new SubscriptionParser(); |
| 131 parser.parse(in, handler); |
| 132 return handler.subscriptions.initialize(); |
| 133 } |
| 134 catch (final ParserConfigurationException | SAXException e) |
| 135 { |
| 136 throw new IOException(e.getClass().getSimpleName() + ": " + e.getMessage()
); |
| 137 } |
| 138 } |
| 139 |
| 140 private static class SubscriptionParser extends DefaultHandler |
| 141 { |
| 142 private boolean inSubscriptions = false; |
| 143 private boolean inVariants = false; |
| 144 |
| 145 private final static String KEY_SUPPLEMENTS = "supplements"; |
| 146 private final static String KEY_SUBSCRIPTIONS = "subscriptions"; |
| 147 private final static String KEY_SUBSCRIPTION = "subscription"; |
| 148 private final static String KEY_VARIANTS = "variants"; |
| 149 private final static String KEY_VARIANT = "variant"; |
| 150 |
| 151 private final DefaultSubscriptions subscriptions = new DefaultSubscriptions(
); |
| 152 private final LinkedList<DefaultSubscriptionInfo> subscriptionStack = new Li
nkedList<>(); |
| 153 private DefaultSubscriptionInfo subscription = null; |
| 154 private DefaultSubscriptionInfo variant = null; |
| 155 |
| 156 @Override |
| 157 public void startElement(final String uri, final String localName, final Str
ing qName, |
| 158 final Attributes attributes) throws SAXException |
| 159 { |
| 160 super.startElement(uri, localName, qName, attributes); |
| 161 |
| 162 if (KEY_SUBSCRIPTIONS.equals(qName)) |
| 163 { |
| 164 this.inSubscriptions = true; |
| 165 } |
| 166 else if (KEY_SUBSCRIPTION.equals(qName)) |
| 167 { |
| 168 if (!this.inSubscriptions) |
| 169 { |
| 170 throw new SAXException("<subscription> outside <subscriptions>"); |
| 171 } |
| 172 if (this.subscription != null) |
| 173 { |
| 174 throw new SAXException("nested <subscription>"); |
| 175 } |
| 176 this.subscription = new DefaultSubscriptionInfo(); |
| 177 for (int i = 0; i < attributes.getLength(); i++) |
| 178 { |
| 179 this.subscription.attributes.put(attributes.getQName(i), attributes.ge
tValue(i)); |
| 180 } |
| 181 } |
| 182 else if (KEY_VARIANTS.equals(qName)) |
| 183 { |
| 184 this.inVariants = true; |
| 185 } |
| 186 else if (KEY_VARIANT.equals(qName)) |
| 187 { |
| 188 if (!this.inVariants) |
| 189 { |
| 190 throw new SAXException("<variant> outside <variants>"); |
| 191 } |
| 192 if (!this.inSubscriptions) |
| 193 { |
| 194 throw new SAXException("<variant> outside <subscriptions>"); |
| 195 } |
| 196 if (this.subscription == null) |
| 197 { |
| 198 throw new SAXException("<variant> outside <subscription>"); |
| 199 } |
| 200 if (this.variant != null) |
| 201 { |
| 202 throw new SAXException("nested <variant>"); |
| 203 } |
| 204 this.variant = new DefaultSubscriptionInfo(); |
| 205 this.variant.attributes.putAll(this.subscription.attributes); |
| 206 for (int i = 0; i < attributes.getLength(); i++) |
| 207 { |
| 208 this.variant.attributes.put(attributes.getQName(i), attributes.getValu
e(i)); |
| 209 } |
| 210 } |
| 211 else if (KEY_SUPPLEMENTS.equals(qName)) |
| 212 { |
| 213 if (!this.inSubscriptions) |
| 214 { |
| 215 throw new SAXException("<supplements> outside <subscriptions>"); |
| 216 } |
| 217 if (this.subscription == null) |
| 218 { |
| 219 throw new SAXException("<supplements> outside <subscription>"); |
| 220 } |
| 221 this.subscriptionStack.addFirst(this.subscription); |
| 222 this.subscription = null; |
| 223 } |
| 224 } |
| 225 |
| 226 @Override |
| 227 public void endElement(final String uri, final String localName, final Strin
g qName) |
| 228 throws SAXException |
| 229 { |
| 230 super.endElement(uri, localName, qName); |
| 231 |
| 232 if (KEY_SUBSCRIPTIONS.equals(qName)) |
| 233 { |
| 234 if (!this.inSubscriptions) |
| 235 { |
| 236 throw new SAXException("</subscriptions> without <subscriptions>"); |
| 237 } |
| 238 this.inSubscriptions = false; |
| 239 } |
| 240 else if (KEY_SUBSCRIPTION.equals(qName)) |
| 241 { |
| 242 if (this.subscription == null) |
| 243 { |
| 244 throw new SAXException("</subscription> without <subscription>"); |
| 245 } |
| 246 if (!this.subscriptionStack.isEmpty()) |
| 247 { |
| 248 this.subscription.parent = this.subscriptionStack.getFirst(); |
| 249 this.subscription.parent.supplements.add(this.subscription); |
| 250 } |
| 251 else |
| 252 { |
| 253 this.subscriptions.subscriptions.add(this.subscription); |
| 254 } |
| 255 this.subscription = null; |
| 256 } |
| 257 else if (KEY_VARIANTS.equals(qName)) |
| 258 { |
| 259 if (!this.inVariants) |
| 260 { |
| 261 throw new SAXException("</variants> without </variants>"); |
| 262 } |
| 263 this.inVariants = false; |
| 264 } |
| 265 else if (KEY_VARIANT.equals(qName)) |
| 266 { |
| 267 if (this.variant == null) |
| 268 { |
| 269 throw new SAXException("</variant> without </variant>"); |
| 270 } |
| 271 |
| 272 this.variant.parent = this.subscription; |
| 273 this.subscription.variants.add(this.variant); |
| 274 |
| 275 this.variant = null; |
| 276 } |
| 277 else if (KEY_SUPPLEMENTS.equals(qName)) |
| 278 { |
| 279 if (this.subscriptionStack.isEmpty()) |
| 280 { |
| 281 throw new SAXException("</supplements> without </supplements>"); |
| 282 } |
| 283 this.subscription = this.subscriptionStack.removeFirst(); |
| 284 } |
| 285 } |
| 286 } |
| 287 |
| 288 @Override |
| 289 public String toString() |
| 290 { |
| 291 return this.linearSubscriptions.toString(); |
| 292 } |
| 293 } |
OLD | NEW |