diff options
-rw-r--r-- | java/src/com/android/inputmethod/latin/DictionaryFactory.java | 18 | ||||
-rw-r--r-- | native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp | 33 | ||||
-rw-r--r-- | native/src/binary_format.h | 13 |
3 files changed, 55 insertions, 9 deletions
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java index a35b0f5b0..f0637b8ce 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java @@ -56,8 +56,11 @@ public class DictionaryFactory { BinaryDictionaryGetter.getDictionaryFiles(locale, context, fallbackResId); if (null != assetFileList) { for (final AssetFileAddress f : assetFileList) { - dictList.add( - new BinaryDictionary(context, f.mFilename, f.mOffset, f.mLength, null)); + final BinaryDictionary binaryDictionary = + new BinaryDictionary(context, f.mFilename, f.mOffset, f.mLength, null); + if (binaryDictionary.isValidDictionary()) { + dictList.add(binaryDictionary); + } } } @@ -67,7 +70,16 @@ public class DictionaryFactory { if (null == dictList) { return new DictionaryCollection(); } else { - return new DictionaryCollection(dictList); + if (dictList.isEmpty()) { + // The list may be empty if no dictionaries have been added. The getter should not + // return an empty list, but if it does we end up here. Likewise, if the files + // we found could not be opened by the native code for any reason (format mismatch, + // file too big to fit in memory, etc) then we could have an empty list. In this + // case we want to fall back on the resource. + return new DictionaryCollection(createBinaryDictionary(context, fallbackResId)); + } else { + return new DictionaryCollection(dictList); + } } } diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index ce874d8d4..18c972444 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "LatinIME: jni: BinaryDictionary" +#include "binary_format.h" #include "com_android_inputmethod_latin_BinaryDictionary.h" #include "dictionary.h" #include "jni.h" @@ -38,6 +39,8 @@ namespace latinime { +void releaseDictBuf(void* dictBuf, const size_t length, int fd); + static jint latinime_BinaryDictionary_open(JNIEnv *env, jobject object, jstring sourceDir, jlong dictOffset, jlong dictSize, jint typedLetterMultiplier, jint fullWordMultiplier, jint maxWordLength, jint maxWords, @@ -104,8 +107,18 @@ static jint latinime_BinaryDictionary_open(JNIEnv *env, jobject object, LOGE("DICT: dictBuf is null"); return 0; } - Dictionary *dictionary = new Dictionary(dictBuf, dictSize, fd, adjust, typedLetterMultiplier, - fullWordMultiplier, maxWordLength, maxWords, maxAlternatives); + Dictionary *dictionary = NULL; + if (BinaryFormat::UNKNOWN_FORMAT == BinaryFormat::detectFormat((uint8_t*)dictBuf)) { + LOGE("DICT: dictionary format is unknown, bad magic number"); +#ifdef USE_MMAP_FOR_DICTIONARY + releaseDictBuf(((char*)dictBuf) - adjust, adjDictSize, fd); +#else // USE_MMAP_FOR_DICTIONARY + releaseDictBuf(dictBuf, 0, 0); +#endif // USE_MMAP_FOR_DICTIONARY + } else { + dictionary = new Dictionary(dictBuf, dictSize, fd, adjust, typedLetterMultiplier, + fullWordMultiplier, maxWordLength, maxWords, maxAlternatives); + } PROF_END(66); PROF_CLOSE; return (jint)dictionary; @@ -180,19 +193,27 @@ static void latinime_BinaryDictionary_close(JNIEnv *env, jobject object, jint di void *dictBuf = dictionary->getDict(); if (!dictBuf) return; #ifdef USE_MMAP_FOR_DICTIONARY - int ret = munmap((void *)((char *)dictBuf - dictionary->getDictBufAdjust()), - dictionary->getDictSize() + dictionary->getDictBufAdjust()); + releaseDictBuf((void *)((char *)dictBuf - dictionary->getDictBufAdjust()), + dictionary->getDictSize() + dictionary->getDictBufAdjust(), dictionary->getMmapFd()); +#else // USE_MMAP_FOR_DICTIONARY + releaseDictBuf(dictBuf, 0, 0); +#endif // USE_MMAP_FOR_DICTIONARY + delete dictionary; +} + +void releaseDictBuf(void* dictBuf, const size_t length, int fd) { +#ifdef USE_MMAP_FOR_DICTIONARY + int ret = munmap(dictBuf, length); if (ret != 0) { LOGE("DICT: Failure in munmap. ret=%d errno=%d", ret, errno); } - ret = close(dictionary->getMmapFd()); + ret = close(fd); if (ret != 0) { LOGE("DICT: Failure in close. ret=%d errno=%d", ret, errno); } #else // USE_MMAP_FOR_DICTIONARY free(dictBuf); #endif // USE_MMAP_FOR_DICTIONARY - delete dictionary; } static JNINativeMethod sMethods[] = { diff --git a/native/src/binary_format.h b/native/src/binary_format.h index e9f108e25..7deec27d3 100644 --- a/native/src/binary_format.h +++ b/native/src/binary_format.h @@ -17,6 +17,8 @@ #ifndef LATINIME_BINARY_FORMAT_H #define LATINIME_BINARY_FORMAT_H +#include "unigram_dictionary.h" + namespace latinime { class BinaryFormat { @@ -26,6 +28,11 @@ private: const static int MULTIPLE_BYTE_CHARACTER_ADDITIONAL_SIZE = 2; public: + const static int UNKNOWN_FORMAT = -1; + const static int FORMAT_VERSION_1 = 1; + const static uint16_t FORMAT_VERSION_1_MAGIC_NUMBER = 0x78B1; + + static int detectFormat(const uint8_t* const dict); static int getGroupCountAndForwardPointer(const uint8_t* const dict, int* pos); static uint8_t getFlagsAndForwardPointer(const uint8_t* const dict, int* pos); static int32_t getCharCodeAndForwardPointer(const uint8_t* const dict, int* pos); @@ -43,6 +50,12 @@ public: int *pos); }; +inline int BinaryFormat::detectFormat(const uint8_t* const dict) { + const uint16_t magicNumber = (dict[0] << 8) + dict[1]; // big endian + if (FORMAT_VERSION_1_MAGIC_NUMBER == magicNumber) return FORMAT_VERSION_1; + return UNKNOWN_FORMAT; +} + inline int BinaryFormat::getGroupCountAndForwardPointer(const uint8_t* const dict, int* pos) { return dict[(*pos)++]; } |