]> gitweb.fperrin.net Git - Dictionary.git/blobdiff - src/com/hughes/android/util/PersistentObjectCache.java
Some lint fixes.
[Dictionary.git] / src / com / hughes / android / util / PersistentObjectCache.java
index a4b8cbfb746b27f0542cc2f2797a5a0e4418d6f2..7ac07458f2cd30ceb23b1e840d7d21859f2a9c45 100644 (file)
@@ -18,84 +18,128 @@ import android.content.Context;
 import android.os.Environment;
 import android.util.Log;
 
+import com.hughes.android.dictionary.DictionaryApplication;
+import com.hughes.android.dictionary.DictionaryInfo;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InvalidClassException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
 public class PersistentObjectCache {
 
-  private final File dir;
-  private final Map<String, Object> objects = new LinkedHashMap<String, Object>();
-  
-  public synchronized <T> T read(final String filename, final Class<T> resultClass) {
-    try {
-      Object object = (objects.get(filename));
-      if (object != null) {
-        return resultClass.cast(object);
-      }
-      Log.d(getClass().getSimpleName(), "Cache miss.");
-      final File src = new File(dir, filename);
-      if (!src.canRead()) {
-        Log.d(getClass().getSimpleName(), "File empty: " + src);
-        return null;
-      }
-      try {
-        final ObjectInputStream in = new ObjectInputStream(new FileInputStream(src));
-        object = in.readObject();
-        in.close();
-      } catch (Exception e) {
-        Log.e(getClass().getSimpleName(), "Deserialization failed: " + src, e);
-        return null;
-      }
-      objects.put(filename, object);
-      return resultClass.cast(object);
-    } catch (ClassCastException e) {
-      return null;
+    private final File dir;
+    private final Map<String, Object> objects = new HashMap<>();
+
+    static class ConstrainedOIS extends ObjectInputStream {
+        ConstrainedOIS(InputStream in) throws IOException {
+            super(in);
+        }
+
+        protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
+            String name = desc.getName();
+            // Note: try to avoid adding more classes.
+            // LinkedHashMap is already more than enough for a DoS
+            if (name.equals(String.class.getName()) ||
+                    name.equals(DictionaryInfo.IndexInfo.class.getName()) ||
+                    name.equals(ArrayList.class.getName()) ||
+                    name.equals(HashMap.class.getName()) ||
+                    name.equals(DictionaryInfo.class.getName()) ||
+                    name.equals(DictionaryApplication.DictionaryConfig.class.getName()) ||
+                    name.equals(LinkedHashMap.class.getName())) {
+                return super.resolveClass(desc);
+            }
+            throw new InvalidClassException("Not allowed to deserialize class", name);
+        }
     }
-  }
-  
-  public synchronized void write(final String filename, final Object object) {
-    objects.put(filename, object);
-    final File dest = new File(dir, filename);
-    try {
-      final ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(dest));
-      out.writeObject(object);
-      out.close();
-    } catch (Exception e) {
-      Log.e(getClass().getSimpleName(), "Serialization failed: " + dest, e);
+
+    public synchronized <T extends Serializable> T read(final String filename, final Class<T> resultClass) {
+        try {
+            Object object = objects.get(filename);
+            if (object != null) {
+                return resultClass.cast(object);
+            }
+            Log.d(getClass().getSimpleName(), "Cache miss.");
+            final File src = new File(dir, filename);
+            if (!src.canRead()) {
+                Log.d(getClass().getSimpleName(), "File empty: " + src);
+                return null;
+            }
+            ObjectInputStream in = null;
+            try {
+                in = new ConstrainedOIS(new BufferedInputStream(new FileInputStream(src)));
+                object = in.readObject();
+                in.close();
+            } catch (Exception e) {
+                Log.e(getClass().getSimpleName(), "Deserialization failed: " + src, e);
+                try {
+                    if (in != null) in.close();
+                } catch (IOException ignored) {}
+                return null;
+            }
+            objects.put(filename, object);
+            return resultClass.cast(object);
+        } catch (ClassCastException e) {
+            return null;
+        }
     }
-  }
 
-  private PersistentObjectCache(final Context context) {
-    final File filesDir = context.getFilesDir();
-    dir = filesDir != null ? filesDir : Environment.getExternalStorageDirectory();
-    if (dir == null) {
-      throw new RuntimeException("context.getFilesDir() == " + context.getFilesDir() + ", Environment.getExternalStorageDirectory()=" + Environment.getExternalStorageDirectory());
+    public synchronized void write(final String filename, final Serializable object) {
+        objects.put(filename, object);
+        final File dest = new File(dir, filename);
+        ObjectOutputStream out = null;
+        try {
+            out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(dest)));
+            out.writeObject(object);
+        } catch (Exception e) {
+            Log.e(getClass().getSimpleName(), "Serialization failed: " + dest, e);
+        }
+        try {
+            if (out != null) out.close();
+        } catch (IOException ignored) {}
     }
-  }
-  
-  public static synchronized PersistentObjectCache getInstance() {
-    if (instance == null) {
-      throw new RuntimeException("getInstance called before init.");
+
+    private PersistentObjectCache(final Context context) {
+        final File filesDir = context.getFilesDir();
+        dir = filesDir != null ? filesDir : Environment.getExternalStorageDirectory();
+        if (dir == null) {
+            throw new RuntimeException("context.getFilesDir() == " + context.getFilesDir()
+                                       + ", Environment.getExternalStorageDirectory()="
+                                       + Environment.getExternalStorageDirectory());
+        }
     }
-    return instance;
-  }
 
-  public static synchronized PersistentObjectCache init(final Context context) {
-      if (instance == null) {
-        instance = new PersistentObjectCache(context);
-      } else {
-        if (!instance.dir.equals(context.getFilesDir())) {
-          throw new RuntimeException("File dir changed.  old=" + instance.dir + ", new=" + context.getFilesDir());
+    public static synchronized PersistentObjectCache getInstance() {
+        if (instance == null) {
+            throw new RuntimeException("getInstance called before init.");
         }
-      }
-      return instance;
-  }
-  
-  private static PersistentObjectCache instance = null;
+        return instance;
+    }
+
+    public static synchronized PersistentObjectCache init(final Context context) {
+        if (instance == null) {
+            instance = new PersistentObjectCache(context);
+        } else {
+            if (!instance.dir.equals(context.getFilesDir())) {
+                throw new RuntimeException("File dir changed.  old=" + instance.dir + ", new="
+                                           + context.getFilesDir());
+            }
+        }
+        return instance;
+    }
+
+    private static PersistentObjectCache instance = null;
 
 }