1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.inputmethod.latin.utils; 18 19 import com.android.inputmethod.annotations.UsedForTesting; 20 import com.android.inputmethod.latin.BinaryDictionary; 21 import com.android.inputmethod.latin.common.StringUtils; 22 import com.android.inputmethod.latin.makedict.DictionaryHeader; 23 import com.android.inputmethod.latin.makedict.UnsupportedFormatException; 24 25 import java.io.File; 26 import java.io.IOException; 27 import java.util.Locale; 28 import java.util.Map; 29 import java.util.regex.Matcher; 30 import java.util.regex.Pattern; 31 32 public final class BinaryDictionaryUtils { 33 private static final String TAG = BinaryDictionaryUtils.class.getSimpleName(); 34 35 private BinaryDictionaryUtils() { 36 // This utility class is not publicly instantiable. 37 } 38 39 static { 40 JniUtils.loadNativeLibrary(); 41 } 42 43 @UsedForTesting 44 private static native boolean createEmptyDictFileNative(String filePath, long dictVersion, 45 String locale, String[] attributeKeyStringArray, String[] attributeValueStringArray); 46 private static native float calcNormalizedScoreNative(int[] before, int[] after, int score); 47 private static native int setCurrentTimeForTestNative(int currentTime); 48 49 public static DictionaryHeader getHeader(final File dictFile) 50 throws IOException, UnsupportedFormatException { 51 return getHeaderWithOffsetAndLength(dictFile, 0 /* offset */, dictFile.length()); 52 } 53 54 public static DictionaryHeader getHeaderWithOffsetAndLength(final File dictFile, 55 final long offset, final long length) throws IOException, UnsupportedFormatException { 56 // dictType is never used for reading the header. Passing an empty string. 57 final BinaryDictionary binaryDictionary = new BinaryDictionary( 58 dictFile.getAbsolutePath(), offset, length, 59 true /* useFullEditDistance */, null /* locale */, "" /* dictType */, 60 false /* isUpdatable */); 61 final DictionaryHeader header = binaryDictionary.getHeader(); 62 binaryDictionary.close(); 63 if (header == null) { 64 throw new IOException(); 65 } 66 return header; 67 } 68 69 public static boolean renameDict(final File dictFile, final File newDictFile) { 70 if (dictFile.isFile()) { 71 return dictFile.renameTo(newDictFile); 72 } else if (dictFile.isDirectory()) { 73 final String dictName = dictFile.getName(); 74 final String newDictName = newDictFile.getName(); 75 if (newDictFile.exists()) { 76 return false; 77 } 78 for (final File file : dictFile.listFiles()) { 79 if (!file.isFile()) { 80 continue; 81 } 82 final String fileName = file.getName(); 83 final String newFileName = fileName.replaceFirst( 84 Pattern.quote(dictName), Matcher.quoteReplacement(newDictName)); 85 if (!file.renameTo(new File(dictFile, newFileName))) { 86 return false; 87 } 88 } 89 return dictFile.renameTo(newDictFile); 90 } 91 return false; 92 } 93 94 @UsedForTesting 95 public static boolean createEmptyDictFile(final String filePath, final long dictVersion, 96 final Locale locale, final Map<String, String> attributeMap) { 97 final String[] keyArray = new String[attributeMap.size()]; 98 final String[] valueArray = new String[attributeMap.size()]; 99 int index = 0; 100 for (final String key : attributeMap.keySet()) { 101 keyArray[index] = key; 102 valueArray[index] = attributeMap.get(key); 103 index++; 104 } 105 return createEmptyDictFileNative(filePath, dictVersion, locale.toString(), keyArray, 106 valueArray); 107 } 108 109 public static float calcNormalizedScore(final String before, final String after, 110 final int score) { 111 return calcNormalizedScoreNative(StringUtils.toCodePointArray(before), 112 StringUtils.toCodePointArray(after), score); 113 } 114 115 /** 116 * Control the current time to be used in the native code. If currentTime >= 0, this method sets 117 * the current time and gets into test mode. 118 * In test mode, set timestamp is used as the current time in the native code. 119 * If currentTime < 0, quit the test mode and returns to using time() to get the current time. 120 * 121 * @param currentTime seconds since the unix epoch 122 * @return current time got in the native code. 123 */ 124 @UsedForTesting 125 public static int setCurrentTimeForTest(final int currentTime) { 126 return setCurrentTimeForTestNative(currentTime); 127 } 128 } 129