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