Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: src/org/adblockplus/sbrowser/contentblocker/engine/Subscription.java

Issue 29372653: Issue 4813 - UTFDataFormatException while serializing filter (Closed)
Patch Set: Including UTF-8 constant and adding migration/file corruption recovery logic Created March 9, 2017, 7:38 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
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)
{

Powered by Google App Engine
This is Rietveld