aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
authorJean Chalard <jchalard@google.com>2011-08-24 16:32:29 +0900
committerJean Chalard <jchalard@google.com>2011-08-24 17:12:12 +0900
commit38d512c0b24f3e5ce595e0b4b9092f84af380517 (patch)
tree604b82bfc60925e94864c8a833b1928768e68565 /java/src
parent8b21eb2507c8db3e8f5ea310bccfe0cb2cd12768 (diff)
downloadlatinime-38d512c0b24f3e5ce595e0b4b9092f84af380517.tar.gz
latinime-38d512c0b24f3e5ce595e0b4b9092f84af380517.tar.xz
latinime-38d512c0b24f3e5ce595e0b4b9092f84af380517.zip
Call the decrypt/unzip routines upon copying a dictionary.
Bug: 5095140 Change-Id: I7000f752bc9b7fd6a7af4839b2f225c085300128
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java143
-rw-r--r--java/src/com/android/inputmethod/latin/FileTransforms.java40
2 files changed, 143 insertions, 40 deletions
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
index 1f756eafb..24bb7b78a 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
@@ -87,29 +87,112 @@ public class BinaryDictionaryFileDumper {
return list;
}
+
/**
- * Caches a word list the id of which is passed as an argument.
+ * Helper method to encapsulate exception handling.
+ */
+ private static AssetFileDescriptor openAssetFileDescriptor(final ContentResolver resolver,
+ final Uri uri) {
+ try {
+ return resolver.openAssetFileDescriptor(uri, "r");
+ } catch (FileNotFoundException e) {
+ // I don't want to log the word list URI here for security concerns
+ Log.e(TAG, "Could not find a word list from the dictionary provider.");
+ return null;
+ }
+ }
+
+ /**
+ * Caches a word list the id of which is passed as an argument. This will write the file
+ * to the cache file name designated by its id and locale, overwriting it if already present
+ * and creating it (and its containing directory) if necessary.
*/
private static AssetFileAddress cacheWordList(final String id, final Locale locale,
final ContentResolver resolver, final Context context) {
+
+ final int COMPRESSED_CRYPTED_COMPRESSED = 0;
+ final int CRYPTED_COMPRESSED = 1;
+ final int COMPRESSED_CRYPTED = 2;
+ final int COMPRESSED_ONLY = 3;
+ final int CRYPTED_ONLY = 4;
+ final int NONE = 5;
+ final int MODE_MIN = COMPRESSED_CRYPTED_COMPRESSED;
+ final int MODE_MAX = NONE;
+
final Uri wordListUri = getProviderUri(id);
- try {
- final AssetFileDescriptor afd = resolver.openAssetFileDescriptor(wordListUri, "r");
- if (null == afd) return null;
- final String fileName = copyFileTo(afd.createInputStream(),
- BinaryDictionaryGetter.getCacheFileName(id, locale, context));
- afd.close();
- if (0 >= resolver.delete(wordListUri, null, null)) {
- // I'd rather not print the word list ID to the log out of security concerns
- Log.e(TAG, "Could not have the dictionary pack delete a word list");
+ final String outputFileName = BinaryDictionaryGetter.getCacheFileName(id, locale, context);
+
+ for (int mode = MODE_MIN; mode <= MODE_MAX; ++mode) {
+ InputStream originalSourceStream = null;
+ InputStream inputStream = null;
+ FileOutputStream outputStream = null;
+ AssetFileDescriptor afd = null;
+ try {
+ // Open input.
+ afd = openAssetFileDescriptor(resolver, wordListUri);
+ // If we can't open it at all, don't even try a number of times.
+ if (null == afd) return null;
+ originalSourceStream = afd.createInputStream();
+ // Open output.
+ outputStream = new FileOutputStream(outputFileName);
+ // Get the appropriate decryption method for this try
+ switch (mode) {
+ case COMPRESSED_CRYPTED_COMPRESSED:
+ inputStream = FileTransforms.getUncompressedStream(
+ FileTransforms.getDecryptedStream(
+ FileTransforms.getUncompressedStream(
+ originalSourceStream)));
+ break;
+ case CRYPTED_COMPRESSED:
+ inputStream = FileTransforms.getUncompressedStream(
+ FileTransforms.getDecryptedStream(originalSourceStream));
+ break;
+ case COMPRESSED_CRYPTED:
+ inputStream = FileTransforms.getDecryptedStream(
+ FileTransforms.getUncompressedStream(originalSourceStream));
+ break;
+ case COMPRESSED_ONLY:
+ inputStream = FileTransforms.getUncompressedStream(originalSourceStream);
+ break;
+ case CRYPTED_ONLY:
+ inputStream = FileTransforms.getDecryptedStream(originalSourceStream);
+ break;
+ case NONE:
+ inputStream = originalSourceStream;
+ break;
+ }
+ copyFileTo(inputStream, outputStream);
+ if (0 >= resolver.delete(wordListUri, null, null)) {
+ Log.e(TAG, "Could not have the dictionary pack delete a word list");
+ }
+ // Success! Close files (through the finally{} clause) and return.
+ return AssetFileAddress.makeFromFileName(outputFileName);
+ } catch (Exception e) {
+ Log.e(TAG, "Can't open word list in mode " + mode + " : " + e);
+ // Try the next method.
+ } finally {
+ // Ignore exceptions while closing files.
+ try {
+ // afd.close() will close inputStream, we should not call inputStream.close().
+ if (null != afd) afd.close();
+ } catch (Exception e) {
+ Log.e(TAG, "Exception while closing a cross-process file descriptor : " + e);
+ }
+ try {
+ if (null != outputStream) outputStream.close();
+ } catch (Exception e) {
+ Log.e(TAG, "Exception while closing a file : " + e);
+ }
}
- return AssetFileAddress.makeFromFileName(fileName);
- } catch (FileNotFoundException e) {
- // This may only come from openAssetFileDescriptor
- return null;
- } catch (IOException e) {
- // Can't read the file for some reason.
- Log.e(TAG, "Cannot read a word list from the dictionary pack : " + e);
+ }
+
+ // We could not copy the file at all. This is very unexpected.
+ // I'd rather not print the word list ID to the log out of security concerns
+ Log.e(TAG, "Could not copy a word list. Will not be able to use it.");
+ // If we can't copy it we should probably delete it to avoid trying to copy it over
+ // and over each time we open LatinIME.
+ if (0 >= resolver.delete(wordListUri, null, null)) {
+ Log.e(TAG, "In addition, we were unable to delete it.");
}
return null;
}
@@ -139,35 +222,15 @@ public class BinaryDictionaryFileDumper {
}
/**
- * Accepts a resource number as dictionary data for some locale and returns the name of a file.
- *
- * This will make the resource the cached dictionary for this locale, overwriting any previous
- * cached data.
- */
- public static String getDictionaryFileFromResource(int resource, Locale locale,
- Context context) throws FileNotFoundException, IOException {
- final Resources res = context.getResources();
- final Locale savedLocale = Utils.setSystemLocale(res, locale);
- final InputStream stream = res.openRawResource(resource);
- Utils.setSystemLocale(res, savedLocale);
- return copyFileTo(stream,
- BinaryDictionaryGetter.getCacheFileName(Integer.toString(resource),
- locale, context));
- }
-
- /**
- * Copies the data in an input stream to a target file, creating the file if necessary and
- * overwriting it if it already exists.
+ * Copies the data in an input stream to a target file.
* @param input the stream to be copied.
- * @param outputFileName the name of a file to copy the data to. It is created if necessary.
+ * @param outputFile an outputstream to copy the data to.
*/
- private static String copyFileTo(final InputStream input, final String outputFileName)
+ private static void copyFileTo(final InputStream input, final FileOutputStream output)
throws FileNotFoundException, IOException {
final byte[] buffer = new byte[FILE_READ_BUFFER_SIZE];
- final FileOutputStream output = new FileOutputStream(outputFileName);
for (int readBytes = input.read(buffer); readBytes >= 0; readBytes = input.read(buffer))
output.write(buffer, 0, readBytes);
input.close();
- return outputFileName;
}
}
diff --git a/java/src/com/android/inputmethod/latin/FileTransforms.java b/java/src/com/android/inputmethod/latin/FileTransforms.java
new file mode 100644
index 000000000..d0374e01e
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/FileTransforms.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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.android.inputmethod.latin;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.zip.GZIPInputStream;
+
+public class FileTransforms {
+ public static OutputStream getCryptedStream(OutputStream out) {
+ // Crypt the stream.
+ return out;
+ }
+
+ public static InputStream getDecryptedStream(InputStream in) {
+ // Decrypt the stream.
+ return in;
+ }
+
+ public static InputStream getUncompressedStream(InputStream in) throws IOException {
+ return new GZIPInputStream(in);
+ }
+}