parent
22f01a42fc
commit
66004ce2de
|
@ -21,8 +21,12 @@ import android.content.SharedPreferences;
|
|||
import android.content.res.AssetFileDescriptor;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.inputmethod.latin.makedict.BinaryDictDecoder;
|
||||
import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils;
|
||||
import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer;
|
||||
import com.android.inputmethod.latin.makedict.FormatSpec;
|
||||
import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
|
||||
import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
|
||||
import com.android.inputmethod.latin.utils.CollectionUtils;
|
||||
import com.android.inputmethod.latin.utils.DictionaryInfoUtils;
|
||||
import com.android.inputmethod.latin.utils.LocaleUtils;
|
||||
|
@ -227,23 +231,14 @@ final public class BinaryDictionaryGetter {
|
|||
// those do not include whitelist entries, the new code with an old version of the dictionary
|
||||
// would lose whitelist functionality.
|
||||
private static boolean hackCanUseDictionaryFile(final Locale locale, final File f) {
|
||||
FileInputStream inStream = null;
|
||||
try {
|
||||
// Read the version of the file
|
||||
inStream = new FileInputStream(f);
|
||||
final BinaryDictDecoderUtils.ByteBufferDictBuffer dictBuffer =
|
||||
new BinaryDictDecoderUtils.ByteBufferDictBuffer(inStream.getChannel().map(
|
||||
FileChannel.MapMode.READ_ONLY, 0, f.length()));
|
||||
final int magic = dictBuffer.readInt();
|
||||
if (magic != FormatSpec.MAGIC_NUMBER) {
|
||||
return false;
|
||||
}
|
||||
final int formatVersion = dictBuffer.readInt();
|
||||
final int headerSize = dictBuffer.readInt();
|
||||
final HashMap<String, String> options = CollectionUtils.newHashMap();
|
||||
BinaryDictDecoderUtils.populateOptions(dictBuffer, headerSize, options);
|
||||
final BinaryDictDecoder dictDecoder = new BinaryDictDecoder(f);
|
||||
dictDecoder.openDictBuffer(
|
||||
new BinaryDictDecoder.DictionaryBufferFromReadOnlyByteBufferFactory());
|
||||
final FileHeader header = dictDecoder.readHeader();
|
||||
|
||||
final String version = options.get(VERSION_KEY);
|
||||
final String version = header.mDictionaryOptions.mAttributes.get(VERSION_KEY);
|
||||
if (null == version) {
|
||||
// No version in the options : the format is unexpected
|
||||
return false;
|
||||
|
@ -259,14 +254,8 @@ final public class BinaryDictionaryGetter {
|
|||
return false;
|
||||
} catch (BufferUnderflowException e) {
|
||||
return false;
|
||||
} finally {
|
||||
if (inStream != null) {
|
||||
try {
|
||||
inStream.close();
|
||||
} catch (IOException e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
} catch (UnsupportedFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,8 @@ package com.android.inputmethod.latin.makedict;
|
|||
import com.android.inputmethod.annotations.UsedForTesting;
|
||||
import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding;
|
||||
import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer;
|
||||
import com.android.inputmethod.latin.makedict.decoder.HeaderReader;
|
||||
import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
|
||||
import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
|
||||
import com.android.inputmethod.latin.utils.ByteArrayDictBuffer;
|
||||
import com.android.inputmethod.latin.utils.JniUtils;
|
||||
|
||||
|
@ -32,8 +33,9 @@ import java.nio.ByteBuffer;
|
|||
import java.nio.channels.FileChannel;
|
||||
import java.util.HashMap;
|
||||
|
||||
// TODO: Rename this class to "Ver3DictDecoder" or something, and make an interface "DictDecoder".
|
||||
@UsedForTesting
|
||||
public class BinaryDictDecoder implements HeaderReader {
|
||||
public class BinaryDictDecoder {
|
||||
|
||||
static {
|
||||
JniUtils.loadNativeLibrary();
|
||||
|
@ -132,6 +134,35 @@ public class BinaryDictDecoder implements HeaderReader {
|
|||
}
|
||||
}
|
||||
|
||||
private final static class HeaderReader {
|
||||
protected static int readVersion(final DictBuffer dictBuffer)
|
||||
throws IOException, UnsupportedFormatException {
|
||||
return BinaryDictDecoderUtils.checkFormatVersion(dictBuffer);
|
||||
}
|
||||
|
||||
protected static int readOptionFlags(final DictBuffer dictBuffer) {
|
||||
return dictBuffer.readUnsignedShort();
|
||||
}
|
||||
|
||||
protected static int readHeaderSize(final DictBuffer dictBuffer) {
|
||||
return dictBuffer.readInt();
|
||||
}
|
||||
|
||||
protected static HashMap<String, String> readAttributes(final DictBuffer dictBuffer,
|
||||
final int headerSize) {
|
||||
final HashMap<String, String> attributes = new HashMap<String, String>();
|
||||
while (dictBuffer.position() < headerSize) {
|
||||
// We can avoid an infinite loop here since dictBuffer.position() is always
|
||||
// increased by calling CharEncoding.readString.
|
||||
final String key = CharEncoding.readString(dictBuffer);
|
||||
final String value = CharEncoding.readString(dictBuffer);
|
||||
attributes.put(key, value);
|
||||
}
|
||||
dictBuffer.position(headerSize);
|
||||
return attributes;
|
||||
}
|
||||
}
|
||||
|
||||
private final File mDictionaryBinaryFile;
|
||||
private DictBuffer mDictBuffer;
|
||||
|
||||
|
@ -157,33 +188,26 @@ public class BinaryDictDecoder implements HeaderReader {
|
|||
return getDictBuffer();
|
||||
}
|
||||
|
||||
// The implementation of HeaderReader
|
||||
@Override
|
||||
public int readVersion() throws IOException, UnsupportedFormatException {
|
||||
return BinaryDictDecoderUtils.checkFormatVersion(mDictBuffer);
|
||||
// TODO : Define public functions of decoders
|
||||
public FileHeader readHeader() throws IOException, UnsupportedFormatException {
|
||||
final int version = HeaderReader.readVersion(mDictBuffer);
|
||||
final int optionsFlags = HeaderReader.readOptionFlags(mDictBuffer);
|
||||
|
||||
final int headerSize = HeaderReader.readHeaderSize(mDictBuffer);
|
||||
|
||||
if (headerSize < 0) {
|
||||
throw new UnsupportedFormatException("header size can't be negative.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readOptionFlags() {
|
||||
return mDictBuffer.readUnsignedShort();
|
||||
}
|
||||
final HashMap<String, String> attributes = HeaderReader.readAttributes(mDictBuffer,
|
||||
headerSize);
|
||||
|
||||
@Override
|
||||
public int readHeaderSize() {
|
||||
return mDictBuffer.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<String, String> readAttributes(final int headerSize) {
|
||||
final HashMap<String, String> attributes = new HashMap<String, String>();
|
||||
while (mDictBuffer.position() < headerSize) {
|
||||
// We can avoid infinite loop here since mFusionDictonary.position() is always increased
|
||||
// by calling CharEncoding.readString.
|
||||
final String key = CharEncoding.readString(mDictBuffer);
|
||||
final String value = CharEncoding.readString(mDictBuffer);
|
||||
attributes.put(key, value);
|
||||
}
|
||||
mDictBuffer.position(headerSize);
|
||||
return attributes;
|
||||
final FileHeader header = new FileHeader(headerSize,
|
||||
new FusionDictionary.DictionaryOptions(attributes,
|
||||
0 != (optionsFlags & FormatSpec.GERMAN_UMLAUT_PROCESSING_FLAG),
|
||||
0 != (optionsFlags & FormatSpec.FRENCH_LIGATURE_PROCESSING_FLAG)),
|
||||
new FormatOptions(version,
|
||||
0 != (optionsFlags & FormatSpec.SUPPORTS_DYNAMIC_UPDATE)));
|
||||
return header;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
|
|||
import com.android.inputmethod.latin.makedict.FusionDictionary.CharGroup;
|
||||
import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
|
||||
import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
|
||||
import com.android.inputmethod.latin.makedict.decoder.HeaderReader;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
|
@ -33,7 +32,6 @@ import java.nio.ByteBuffer;
|
|||
import java.nio.channels.FileChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
|
@ -639,49 +637,6 @@ public final class BinaryDictDecoderUtils {
|
|||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a header from a buffer.
|
||||
* @param headerReader the header reader
|
||||
* @throws IOException
|
||||
* @throws UnsupportedFormatException
|
||||
*/
|
||||
public static FileHeader readHeader(final HeaderReader headerReader)
|
||||
throws IOException, UnsupportedFormatException {
|
||||
final int version = headerReader.readVersion();
|
||||
final int optionsFlags = headerReader.readOptionFlags();
|
||||
|
||||
final int headerSize = headerReader.readHeaderSize();
|
||||
|
||||
if (headerSize < 0) {
|
||||
throw new UnsupportedFormatException("header size can't be negative.");
|
||||
}
|
||||
|
||||
final HashMap<String, String> attributes = headerReader.readAttributes(headerSize);
|
||||
|
||||
final FileHeader header = new FileHeader(headerSize,
|
||||
new FusionDictionary.DictionaryOptions(attributes,
|
||||
0 != (optionsFlags & FormatSpec.GERMAN_UMLAUT_PROCESSING_FLAG),
|
||||
0 != (optionsFlags & FormatSpec.FRENCH_LIGATURE_PROCESSING_FLAG)),
|
||||
new FormatOptions(version,
|
||||
0 != (optionsFlags & FormatSpec.SUPPORTS_DYNAMIC_UPDATE)));
|
||||
return header;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads options from a buffer and populate a map with their contents.
|
||||
*
|
||||
* The buffer is read at the current position, so the caller must take care the pointer
|
||||
* is in the right place before calling this.
|
||||
*/
|
||||
public static void populateOptions(final DictBuffer dictBuffer,
|
||||
final int headerSize, final HashMap<String, String> options) {
|
||||
while (dictBuffer.position() < headerSize) {
|
||||
final String key = CharEncoding.readString(dictBuffer);
|
||||
final String value = CharEncoding.readString(dictBuffer);
|
||||
options.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a buffer and returns the memory representation of the dictionary.
|
||||
*
|
||||
|
@ -706,7 +661,7 @@ public final class BinaryDictDecoderUtils {
|
|||
}
|
||||
|
||||
// Read header
|
||||
final FileHeader fileHeader = readHeader(dictDecoder);
|
||||
final FileHeader fileHeader = dictDecoder.readHeader();
|
||||
|
||||
Map<Integer, PtNodeArray> reverseNodeArrayMapping = new TreeMap<Integer, PtNodeArray>();
|
||||
Map<Integer, CharGroup> reverseGroupMapping = new TreeMap<Integer, CharGroup>();
|
||||
|
|
|
@ -153,7 +153,7 @@ public final class BinaryDictIOUtils {
|
|||
final Map<Integer, ArrayList<PendingAttribute>> bigrams) throws IOException,
|
||||
UnsupportedFormatException {
|
||||
// Read header
|
||||
final FileHeader header = BinaryDictDecoderUtils.readHeader(dictDecoder);
|
||||
final FileHeader header = dictDecoder.readHeader();
|
||||
readUnigramsAndBigramsBinaryInner(dictDecoder.getDictBuffer(), header.mHeaderSize, words,
|
||||
frequencies, bigrams, header.mFormatOptions);
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ public final class BinaryDictIOUtils {
|
|||
if (word == null) return FormatSpec.NOT_VALID_WORD;
|
||||
if (dictBuffer.position() != 0) dictBuffer.position(0);
|
||||
|
||||
final FileHeader header = BinaryDictDecoderUtils.readHeader(dictDecoder);
|
||||
final FileHeader header = dictDecoder.readHeader();
|
||||
int wordPos = 0;
|
||||
final int wordLen = word.codePointCount(0, word.length());
|
||||
for (int depth = 0; depth < Constants.DICTIONARY_MAX_WORD_LENGTH; ++depth) {
|
||||
|
@ -523,7 +523,7 @@ public final class BinaryDictIOUtils {
|
|||
final DictBuffer dictBuffer = dictDecoder.getDictBuffer();
|
||||
if (position != FormatSpec.NOT_VALID_WORD) {
|
||||
dictBuffer.position(0);
|
||||
final FileHeader header = BinaryDictDecoderUtils.readHeader(dictDecoder);
|
||||
final FileHeader header = dictDecoder.readHeader();
|
||||
dictBuffer.position(position);
|
||||
return BinaryDictDecoderUtils.readCharGroup(dictBuffer, position,
|
||||
header.mFormatOptions);
|
||||
|
@ -559,7 +559,7 @@ public final class BinaryDictIOUtils {
|
|||
}
|
||||
}
|
||||
});
|
||||
return BinaryDictDecoderUtils.readHeader(dictDecoder);
|
||||
return dictDecoder.readHeader();
|
||||
}
|
||||
|
||||
public static FileHeader getDictionaryFileHeaderOrNull(final File file, final long offset,
|
||||
|
|
|
@ -59,7 +59,7 @@ public final class DynamicBinaryDictIOUtils {
|
|||
throws IOException, UnsupportedFormatException {
|
||||
final DictBuffer dictBuffer = dictDecoder.getDictBuffer();
|
||||
dictBuffer.position(0);
|
||||
final FileHeader header = BinaryDictDecoderUtils.readHeader(dictDecoder);
|
||||
final FileHeader header = dictDecoder.readHeader();
|
||||
final int wordPosition = BinaryDictIOUtils.getTerminalPosition(dictDecoder, word);
|
||||
if (wordPosition == FormatSpec.NOT_VALID_WORD) return;
|
||||
|
||||
|
@ -278,7 +278,7 @@ public final class DynamicBinaryDictIOUtils {
|
|||
|
||||
// find the insert position of the word.
|
||||
if (dictBuffer.position() != 0) dictBuffer.position(0);
|
||||
final FileHeader fileHeader = BinaryDictDecoderUtils.readHeader(dictDecoder);
|
||||
final FileHeader fileHeader = dictDecoder.readHeader();
|
||||
|
||||
int wordPos = 0, address = dictBuffer.position(), nodeOriginAddress = dictBuffer.position();
|
||||
final int[] codePoints = FusionDictionary.getCodePoints(word);
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.inputmethod.latin.makedict.decoder;
|
||||
|
||||
import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* An interface to read a binary dictionary file header.
|
||||
*/
|
||||
public interface HeaderReader {
|
||||
public int readVersion() throws IOException, UnsupportedFormatException;
|
||||
public int readOptionFlags();
|
||||
public int readHeaderSize();
|
||||
public HashMap<String, String> readAttributes(final int headerSize);
|
||||
}
|
|
@ -505,7 +505,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
|
|||
|
||||
FileHeader fileHeader = null;
|
||||
try {
|
||||
fileHeader = BinaryDictDecoderUtils.readHeader(dictDecoder);
|
||||
fileHeader = dictDecoder.readHeader();
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
} catch (UnsupportedFormatException e) {
|
||||
|
|
|
@ -130,7 +130,7 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase {
|
|||
|
||||
private static void printBinaryFile(final BinaryDictDecoder dictDecoder)
|
||||
throws IOException, UnsupportedFormatException {
|
||||
final FileHeader fileHeader = BinaryDictDecoderUtils.readHeader(dictDecoder);
|
||||
final FileHeader fileHeader = dictDecoder.readHeader();
|
||||
final DictBuffer buffer = dictDecoder.getDictBuffer();
|
||||
while (buffer.position() < buffer.limit()) {
|
||||
printNode(buffer, fileHeader.mFormatOptions);
|
||||
|
@ -225,7 +225,7 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase {
|
|||
try {
|
||||
final DictBuffer dictBuffer = dictDecoder.openAndGetDictBuffer(
|
||||
new BinaryDictDecoder.DictionaryBufferFromReadOnlyByteBufferFactory());
|
||||
final FileHeader fileHeader = BinaryDictDecoderUtils.readHeader(dictDecoder);
|
||||
final FileHeader fileHeader = dictDecoder.readHeader();
|
||||
assertEquals(word,
|
||||
BinaryDictDecoderUtils.getWordAtAddress(dictDecoder.getDictBuffer(),
|
||||
fileHeader.mHeaderSize, position - fileHeader.mHeaderSize,
|
||||
|
|
Loading…
Reference in New Issue