| Index: src/org/adblockplus/sbrowser/contentblocker/engine/Subscription.java |
| =================================================================== |
| --- a/src/org/adblockplus/sbrowser/contentblocker/engine/Subscription.java |
| +++ b/src/org/adblockplus/sbrowser/contentblocker/engine/Subscription.java |
| @@ -37,16 +37,17 @@ import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.zip.GZIPInputStream; |
| import java.util.zip.GZIPOutputStream; |
| +import android.text.TextUtils; |
| import android.util.Log; |
| /** |
| * Simple subscription representation. |
| */ |
| final class Subscription |
| { |
| private static final String TAG = Subscription.class.getSimpleName(); |
| @@ -78,17 +79,17 @@ final class Subscription |
| private static final String[] ALLOWED_META_KEYS_ARRAY = |
| { |
| "checksum", KEY_VERSION, KEY_TITLE, "last modified", "expires", "homepage", "licence" |
| }; |
| private final URL url; |
| private final Type type; |
| private final HashMap<String, String> meta = new HashMap<String, String>(); |
| - private HashSet<String> filters = null; |
| + private final HashSet<String> filters = new HashSet<String>(); |
| private boolean metaDataValid = true; |
| private boolean filtersValid = true; |
| static |
| { |
| for (final String s : ALLOWED_META_KEYS_ARRAY) |
| { |
| @@ -315,27 +316,27 @@ final class Subscription |
| return "true".equals(this.getMeta(KEY_ENABLED)); |
| } |
| public void setEnabled(boolean enable) |
| { |
| this.putMeta(KEY_ENABLED, Boolean.toString(enable)); |
| } |
| - public void getFilters(Collection<String> filters) |
| + public void copyFilters(Collection<String> filters) |
| { |
| - if (this.filters != null) |
| + if (filters != null) |
| { |
| filters.addAll(this.filters); |
| } |
| } |
| public void clearFilters() |
| { |
| - this.filters = null; |
| + this.filters.clear(); |
| } |
| /** |
| * @return an internal management ID |
| */ |
| public String getId() |
| { |
| return getId(this); |
| @@ -384,17 +385,17 @@ final class Subscription |
| private static String createFilterHash(List<String> filters) throws IOException |
| { |
| try |
| { |
| final MessageDigest md5 = MessageDigest.getInstance("MD5"); |
| Collections.sort(filters); |
| for (final String filter : filters) |
| { |
| - md5.update(filter.getBytes("UTF-8")); |
| + md5.update(filter.getBytes(Engine.CHARSET_UTF_8)); |
| } |
| return byteArrayToHexString(md5.digest()); |
| } |
| catch (final NoSuchAlgorithmException e) |
| { |
| throw new IOException("MD5 is unavailable: " + e.getMessage(), e); |
| } |
| } |
| @@ -421,109 +422,128 @@ final class Subscription |
| } |
| public void serializeFilters(final File filtersFile) throws IOException |
| { |
| final DataOutputStream filtersOut = new DataOutputStream(new GZIPOutputStream( |
| new BufferedOutputStream(new FileOutputStream(filtersFile)))); |
| try |
| { |
| - if (this.filters == null) |
| - { |
| - filtersOut.writeInt(0); |
| - } |
| - else |
| + filtersOut.writeInt(this.filters.size()); |
| + filtersOut.writeUTF(createFilterHash(new ArrayList<String>(this.filters))); |
| + for (final String s : this.filters) |
| { |
| - filtersOut.writeInt(this.filters.size()); |
| - filtersOut.writeUTF(createFilterHash(new ArrayList<String>(this.filters))); |
| - for (final String s : this.filters) |
| - { |
| - filtersOut.writeUTF(s); |
| - } |
| + final byte[] b = s.getBytes(Engine.CHARSET_UTF_8); |
| + filtersOut.writeInt(b.length); |
| + filtersOut.write(b); |
| } |
| } |
| finally |
| { |
| filtersOut.close(); |
| } |
| } |
| public void serializeSubscription(final File metaFile, final File filtersFile) throws IOException |
| { |
| this.serializeMetaData(metaFile); |
| this.serializeFilters(filtersFile); |
| } |
| - public static Subscription deserializeSubscription(final File metaFile) throws IOException |
| + public static Subscription deserializeSubscription(final File metaFile) |
| { |
| - final DataInputStream in = new DataInputStream(new GZIPInputStream(new BufferedInputStream( |
| - new FileInputStream(metaFile)))); |
| + Subscription sub = null; |
| + DataInputStream in = null; |
| try |
| { |
| + in = new DataInputStream(new GZIPInputStream(new BufferedInputStream( |
| + new FileInputStream(metaFile)))); |
| final String urlString = in.readUTF(); |
| - final Subscription sub = new Subscription(urlString.length() > 0 ? new URL(urlString) : null); |
| + sub = new Subscription(!TextUtils.isEmpty(urlString) ? new URL(urlString) : null); |
| + sub.metaDataValid = false; |
| final int numMetaEntries = in.readInt(); |
| for (int i = 0; i < numMetaEntries; i++) |
| { |
| final String key = in.readUTF(); |
| final String value = in.readUTF(); |
| sub.meta.put(key, value); |
| } |
| sub.metaDataValid = createMetaDataHash(sub.meta).equals(sub.getMeta(KEY_META_HASH)); |
| - return sub; |
| + } |
| + catch (Throwable t) |
| + { |
| + // We catch Throwable here in order to return whatever we could retrieve from the meta file |
| } |
| finally |
| { |
| - in.close(); |
| + if (in != null) |
| + { |
| + try |
| + { |
| + in.close(); |
| + } |
| + catch (IOException e) |
| + { |
| + // Ignored |
| + } |
| + } |
| } |
| + return sub; |
| } |
| - public void deserializeFilters(final File filtersFile) throws IOException |
| + public void deserializeFilters(final File filtersFile) |
| { |
| - final DataInputStream in = new DataInputStream(new GZIPInputStream(new BufferedInputStream( |
| - new FileInputStream(filtersFile)))); |
| + this.clearFilters(); |
| + this.filtersValid = false; |
| + DataInputStream in = null; |
| try |
| { |
| + in = new DataInputStream(new GZIPInputStream(new BufferedInputStream( |
| + new FileInputStream(filtersFile)))); |
| final int numFilters = in.readInt(); |
| - if (numFilters == 0) |
| - { |
| - this.filters = null; |
| - } |
| - else |
| + final String filtersHash = in.readUTF(); |
| + for (int i = 0; i < numFilters; i++) |
| { |
| - this.filters = new HashSet<String>(); |
| - final String filtersHash = in.readUTF(); |
| - for (int i = 0; i < numFilters; i++) |
| - { |
| - this.filters.add(in.readUTF()); |
| - } |
| - this.filtersValid = createFilterHash(new ArrayList<String>(this.filters)).equals( |
| - filtersHash); |
| - Log.d(TAG, "Filters valid: " + this.filtersValid); |
| + final int length = in.readInt(); |
| + final byte[] b = new byte[length]; |
| + in.readFully(b); |
| + this.filters.add(new String(b, Engine.CHARSET_UTF_8)); |
| } |
| + this.filtersValid = createFilterHash(new ArrayList<String>(this.filters)).equals( |
| + filtersHash); |
| + Log.d(TAG, "Filters valid: " + this.filtersValid); |
| + } |
| + catch (Throwable t) |
| + { |
| + // We catch Throwable here in order to load whatever we could retrieve from the filters file |
| } |
| finally |
| { |
| - in.close(); |
| + if (in != null) |
| + { |
| + try |
| + { |
| + in.close(); |
| + } |
| + catch (IOException e) |
| + { |
| + // Ignored |
| + } |
| + } |
| } |
| } |
| /** |
| * Adds the given string, which should be a single filter to this |
| * subscription. |
| * |
| * @param input |
| */ |
| public Subscription parseLine(String input) |
| { |
| - if (this.filters == null) |
| - { |
| - this.filters = new HashSet<String>(); |
| - } |
| - |
| final String line = input.trim(); |
| if (!line.isEmpty()) |
| { |
| if (line.startsWith("!")) |
| { |
| // Meta data |
| final int colon = line.indexOf(':'); |
| if (colon > 2) |
| @@ -616,17 +636,17 @@ final class Subscription |
| this.meta.put(KEY_HTTP_LAST_MODIFIED, lastModified); |
| } |
| else |
| { |
| this.meta.remove(KEY_HTTP_LAST_MODIFIED); |
| } |
| this.meta.put(KEY_DOWNLOAD_COUNT, Long.toString(this.getDownloadCount() + 1)); |
| - this.filters = new HashSet<String>(); |
| + this.clearFilters(); |
| this.parseText(text); |
| } |
| } |
| } |
| this.serializeMetaData(metaFile); |
| if (filtersChanged) |
| { |