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.makedict.BinaryDictDecoderUtils.DictBuffer; 21 import com.android.inputmethod.latin.utils.ByteArrayDictBuffer; 22 23 import java.io.File; 24 import java.io.FileInputStream; 25 import java.io.FileNotFoundException; 26 import java.io.IOException; 27 import java.io.RandomAccessFile; 28 import java.nio.ByteBuffer; 29 import java.nio.channels.FileChannel; 30 import java.util.ArrayList; 31 import java.util.TreeMap; 32 33 /** 34 * An interface of binary dictionary decoders. 35 */ 36 // TODO: Straighten out responsibility for the buffer's file pointer. 37 public interface DictDecoder { 38 39 /** 40 * Reads and returns the file header. 41 */ readHeader()42 public DictionaryHeader readHeader() throws IOException, UnsupportedFormatException; 43 44 /** 45 * Reads PtNode from ptNodePos. 46 * @param ptNodePos the position of PtNode. 47 * @return PtNodeInfo. 48 */ readPtNode(final int ptNodePos)49 public PtNodeInfo readPtNode(final int ptNodePos); 50 51 /** 52 * Reads a buffer and returns the memory representation of the dictionary. 53 * 54 * This high-level method takes a buffer and reads its contents, populating a 55 * FusionDictionary structure. 56 * 57 * @param deleteDictIfBroken a flag indicating whether this method should remove the broken 58 * dictionary or not. 59 * @return the created dictionary. 60 */ 61 @UsedForTesting readDictionaryBinary(final boolean deleteDictIfBroken)62 public FusionDictionary readDictionaryBinary(final boolean deleteDictIfBroken) 63 throws FileNotFoundException, IOException, UnsupportedFormatException; 64 65 /** 66 * Gets the address of the last PtNode of the exact matching word in the dictionary. 67 * If no match is found, returns NOT_VALID_WORD. 68 * 69 * @param word the word we search for. 70 * @return the address of the terminal node. 71 * @throws IOException if the file can't be read. 72 * @throws UnsupportedFormatException if the format of the file is not recognized. 73 */ 74 @UsedForTesting getTerminalPosition(final String word)75 public int getTerminalPosition(final String word) 76 throws IOException, UnsupportedFormatException; 77 78 /** 79 * Reads unigrams and bigrams from the binary file. 80 * Doesn't store a full memory representation of the dictionary. 81 * 82 * @param words the map to store the address as a key and the word as a value. 83 * @param frequencies the map to store the address as a key and the frequency as a value. 84 * @param bigrams the map to store the address as a key and the list of address as a value. 85 * @throws IOException if the file can't be read. 86 * @throws UnsupportedFormatException if the format of the file is not recognized. 87 */ 88 @UsedForTesting readUnigramsAndBigramsBinary(final TreeMap<Integer, String> words, final TreeMap<Integer, Integer> frequencies, final TreeMap<Integer, ArrayList<PendingAttribute>> bigrams)89 public void readUnigramsAndBigramsBinary(final TreeMap<Integer, String> words, 90 final TreeMap<Integer, Integer> frequencies, 91 final TreeMap<Integer, ArrayList<PendingAttribute>> bigrams) 92 throws IOException, UnsupportedFormatException; 93 94 /** 95 * Sets the position of the buffer to the given value. 96 * 97 * @param newPos the new position 98 */ setPosition(final int newPos)99 public void setPosition(final int newPos); 100 101 /** 102 * Gets the position of the buffer. 103 * 104 * @return the position 105 */ getPosition()106 public int getPosition(); 107 108 /** 109 * Reads and returns the PtNode count out of a buffer and forwards the pointer. 110 */ readPtNodeCount()111 public int readPtNodeCount(); 112 113 /** 114 * Opens the dictionary file and makes DictBuffer. 115 */ 116 @UsedForTesting openDictBuffer()117 public void openDictBuffer() throws FileNotFoundException, IOException, 118 UnsupportedFormatException; 119 @UsedForTesting isDictBufferOpen()120 public boolean isDictBufferOpen(); 121 122 // Constants for DictionaryBufferFactory. 123 public static final int USE_READONLY_BYTEBUFFER = 0x01000000; 124 public static final int USE_BYTEARRAY = 0x02000000; 125 public static final int USE_WRITABLE_BYTEBUFFER = 0x03000000; 126 public static final int MASK_DICTBUFFER = 0x0F000000; 127 128 public interface DictionaryBufferFactory { getDictionaryBuffer(final File file)129 public DictBuffer getDictionaryBuffer(final File file) 130 throws FileNotFoundException, IOException; 131 } 132 133 /** 134 * Creates DictionaryBuffer using a ByteBuffer 135 * 136 * This class uses less memory than DictionaryBufferFromByteArrayFactory, 137 * but doesn't perform as fast. 138 * When operating on a big dictionary, this class is preferred. 139 */ 140 public static final class DictionaryBufferFromReadOnlyByteBufferFactory 141 implements DictionaryBufferFactory { 142 @Override getDictionaryBuffer(final File file)143 public DictBuffer getDictionaryBuffer(final File file) 144 throws FileNotFoundException, IOException { 145 FileInputStream inStream = null; 146 ByteBuffer buffer = null; 147 try { 148 inStream = new FileInputStream(file); 149 buffer = inStream.getChannel().map(FileChannel.MapMode.READ_ONLY, 150 0, file.length()); 151 } finally { 152 if (inStream != null) { 153 inStream.close(); 154 } 155 } 156 if (buffer != null) { 157 return new BinaryDictDecoderUtils.ByteBufferDictBuffer(buffer); 158 } 159 return null; 160 } 161 } 162 163 /** 164 * Creates DictionaryBuffer using a byte array 165 * 166 * This class performs faster than other classes, but consumes more memory. 167 * When operating on a small dictionary, this class is preferred. 168 */ 169 public static final class DictionaryBufferFromByteArrayFactory 170 implements DictionaryBufferFactory { 171 @Override getDictionaryBuffer(final File file)172 public DictBuffer getDictionaryBuffer(final File file) 173 throws FileNotFoundException, IOException { 174 FileInputStream inStream = null; 175 try { 176 inStream = new FileInputStream(file); 177 final byte[] array = new byte[(int) file.length()]; 178 inStream.read(array); 179 return new ByteArrayDictBuffer(array); 180 } finally { 181 if (inStream != null) { 182 inStream.close(); 183 } 184 } 185 } 186 } 187 188 /** 189 * Creates DictionaryBuffer using a writable ByteBuffer and a RandomAccessFile. 190 * 191 * This class doesn't perform as fast as other classes, 192 * but this class is the only option available for destructive operations (insert or delete) 193 * on a dictionary. 194 */ 195 @UsedForTesting 196 public static final class DictionaryBufferFromWritableByteBufferFactory 197 implements DictionaryBufferFactory { 198 @Override getDictionaryBuffer(final File file)199 public DictBuffer getDictionaryBuffer(final File file) 200 throws FileNotFoundException, IOException { 201 RandomAccessFile raFile = null; 202 ByteBuffer buffer = null; 203 try { 204 raFile = new RandomAccessFile(file, "rw"); 205 buffer = raFile.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, file.length()); 206 } finally { 207 if (raFile != null) { 208 raFile.close(); 209 } 210 } 211 if (buffer != null) { 212 return new BinaryDictDecoderUtils.ByteBufferDictBuffer(buffer); 213 } 214 return null; 215 } 216 } 217 218 /** 219 * @return whether this decoder has a valid binary dictionary that it can decode. 220 */ hasValidRawBinaryDictionary()221 public boolean hasValidRawBinaryDictionary(); 222 } 223