X-Git-Url: http://gitweb.fperrin.net/?p=Dictionary.git;a=blobdiff_plain;f=src%2Fcom%2Fhughes%2Fandroid%2Futil%2FPersistentObjectCache.java;h=7ac07458f2cd30ceb23b1e840d7d21859f2a9c45;hp=2d9d2ff9910dd484e2895d36c76aff426fc4db2b;hb=e79165503392ed6a7cb7a8eadc15eaae0cda9443;hpb=63dc6ebb11356f45e95fe59069dc39649b592cfa diff --git a/src/com/hughes/android/util/PersistentObjectCache.java b/src/com/hughes/android/util/PersistentObjectCache.java index 2d9d2ff..7ac0745 100644 --- a/src/com/hughes/android/util/PersistentObjectCache.java +++ b/src/com/hughes/android/util/PersistentObjectCache.java @@ -1,78 +1,145 @@ +// Copyright 2011 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package com.hughes.android.util; +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; -import android.content.Context; -import android.util.Log; - public class PersistentObjectCache { - private final File dir; - private final Map objects = new LinkedHashMap(); - - public synchronized Object read(final String filename) { - Object object = (objects.get(filename)); - if (object != null) { - return object; + private final File dir; + private final Map 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); + } } - 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; + + public synchronized T read(final String filename, final Class 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; + } } - 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; + + 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) {} } - objects.put(filename, object); - return object; - } - - 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); + + 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()); + } } - } - private PersistentObjectCache(final Context context) { - dir = context.getFilesDir(); - } - - public static synchronized PersistentObjectCache getInstance() { - if (instance == null) { - throw new RuntimeException("getInstance called before init."); + public static synchronized PersistentObjectCache getInstance() { + if (instance == null) { + throw new RuntimeException("getInstance called before init."); + } + return instance; } - 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 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; + return instance; + } + + private static PersistentObjectCache instance = null; }