1 /* 2 * Copyright (C) 2013 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.makedict; 18 19 import com.android.inputmethod.annotations.UsedForTesting; 20 import com.android.inputmethod.latin.BinaryDictionary; 21 import com.android.inputmethod.latin.Dictionary; 22 import com.android.inputmethod.latin.NgramContext; 23 import com.android.inputmethod.latin.common.LocaleUtils; 24 import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; 25 import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; 26 import com.android.inputmethod.latin.utils.BinaryDictionaryUtils; 27 28 import java.io.File; 29 import java.io.IOException; 30 import java.util.HashMap; 31 32 /** 33 * An implementation of DictEncoder for version 4 binary dictionary. 34 */ 35 @UsedForTesting 36 public class Ver4DictEncoder implements DictEncoder { 37 private final File mDictPlacedDir; 38 39 @UsedForTesting Ver4DictEncoder(final File dictPlacedDir)40 public Ver4DictEncoder(final File dictPlacedDir) { 41 mDictPlacedDir = dictPlacedDir; 42 } 43 44 // TODO: This builds a FusionDictionary first and iterates it to add words to the binary 45 // dictionary. However, it is possible to just add words directly to the binary dictionary 46 // instead. 47 // In the long run, when we stop supporting version 2, FusionDictionary will become deprecated 48 // and we can remove it. Then we'll be able to just call BinaryDictionary directly. 49 @Override writeDictionary(FusionDictionary dict, FormatOptions formatOptions)50 public void writeDictionary(FusionDictionary dict, FormatOptions formatOptions) 51 throws IOException, UnsupportedFormatException { 52 if (formatOptions.mVersion != FormatSpec.VERSION4) { 53 throw new UnsupportedFormatException("File header has a wrong version number : " 54 + formatOptions.mVersion); 55 } 56 if (!mDictPlacedDir.isDirectory()) { 57 throw new UnsupportedFormatException("Given path is not a directory."); 58 } 59 if (!BinaryDictionaryUtils.createEmptyDictFile(mDictPlacedDir.getAbsolutePath(), 60 FormatSpec.VERSION4, LocaleUtils.constructLocaleFromString( 61 dict.mOptions.mAttributes.get(DictionaryHeader.DICTIONARY_LOCALE_KEY)), 62 dict.mOptions.mAttributes)) { 63 throw new IOException("Cannot create dictionary file : " 64 + mDictPlacedDir.getAbsolutePath()); 65 } 66 final BinaryDictionary binaryDict = new BinaryDictionary(mDictPlacedDir.getAbsolutePath(), 67 0l, mDictPlacedDir.length(), true /* useFullEditDistance */, 68 LocaleUtils.constructLocaleFromString(dict.mOptions.mAttributes.get( 69 DictionaryHeader.DICTIONARY_LOCALE_KEY)), 70 Dictionary.TYPE_USER /* Dictionary type. Does not matter for us */, 71 true /* isUpdatable */); 72 if (!binaryDict.isValidDictionary()) { 73 // Somehow createEmptyDictFile returned true, but the file was not created correctly 74 throw new IOException("Cannot create dictionary file"); 75 } 76 for (final WordProperty wordProperty : dict) { 77 if (!binaryDict.addUnigramEntry(wordProperty.mWord, wordProperty.getProbability(), 78 wordProperty.mIsBeginningOfSentence, wordProperty.mIsNotAWord, 79 wordProperty.mIsPossiblyOffensive, 0 /* timestamp */)) { 80 MakedictLog.e("Cannot add unigram entry for " + wordProperty.mWord); 81 } 82 if (binaryDict.needsToRunGC(true /* mindsBlockByGC */)) { 83 if (!binaryDict.flushWithGC()) { 84 MakedictLog.e("Cannot flush dict with GC."); 85 return; 86 } 87 } 88 } 89 for (final WordProperty word0Property : dict) { 90 if (!word0Property.mHasNgrams) continue; 91 // TODO: Support ngram. 92 for (final WeightedString word1 : word0Property.getBigrams()) { 93 final NgramContext ngramContext = 94 new NgramContext(new NgramContext.WordInfo(word0Property.mWord)); 95 if (!binaryDict.addNgramEntry(ngramContext, word1.mWord, 96 word1.getProbability(), 0 /* timestamp */)) { 97 MakedictLog.e("Cannot add n-gram entry for " 98 + ngramContext + " -> " + word1.mWord); 99 return; 100 } 101 if (binaryDict.needsToRunGC(true /* mindsBlockByGC */)) { 102 if (!binaryDict.flushWithGC()) { 103 MakedictLog.e("Cannot flush dict with GC."); 104 return; 105 } 106 } 107 } 108 } 109 if (!binaryDict.flushWithGC()) { 110 MakedictLog.e("Cannot flush dict with GC."); 111 return; 112 } 113 binaryDict.close(); 114 } 115 116 @Override setPosition(int position)117 public void setPosition(int position) { 118 } 119 120 @Override getPosition()121 public int getPosition() { 122 return 0; 123 } 124 125 @Override writePtNodeCount(int ptNodeCount)126 public void writePtNodeCount(int ptNodeCount) { 127 } 128 129 @Override writePtNode(PtNode ptNode, FusionDictionary dict, HashMap<Integer, Integer> codePointToOneByteCodeMap)130 public void writePtNode(PtNode ptNode, FusionDictionary dict, 131 HashMap<Integer, Integer> codePointToOneByteCodeMap) { 132 } 133 } 134