parent
f2773ba76b
commit
107a5f6fb8
|
@ -278,6 +278,12 @@ public final class BinaryDictDecoderUtils {
|
||||||
// Input methods: Read a binary dictionary to memory.
|
// Input methods: Read a binary dictionary to memory.
|
||||||
// readDictionaryBinary is the public entry point for them.
|
// readDictionaryBinary is the public entry point for them.
|
||||||
|
|
||||||
|
static int readSInt24(final DictBuffer dictBuffer) {
|
||||||
|
final int retval = dictBuffer.readUnsignedInt24();
|
||||||
|
final int sign = ((retval & FormatSpec.MSB24) != 0) ? -1 : 1;
|
||||||
|
return sign * (retval & FormatSpec.SINT24_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
static int readChildrenAddress(final DictBuffer dictBuffer,
|
static int readChildrenAddress(final DictBuffer dictBuffer,
|
||||||
final int optionFlags, final FormatOptions options) {
|
final int optionFlags, final FormatOptions options) {
|
||||||
if (options.mSupportsDynamicUpdate) {
|
if (options.mSupportsDynamicUpdate) {
|
||||||
|
@ -314,103 +320,6 @@ public final class BinaryDictDecoderUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int[] CHARACTER_BUFFER = new int[FormatSpec.MAX_WORD_LENGTH];
|
|
||||||
public static CharGroupInfo readCharGroup(final DictBuffer dictBuffer,
|
|
||||||
final int originalGroupAddress, final FormatOptions options) {
|
|
||||||
int addressPointer = originalGroupAddress;
|
|
||||||
final int flags = dictBuffer.readUnsignedByte();
|
|
||||||
++addressPointer;
|
|
||||||
|
|
||||||
final int parentAddress = readParentAddress(dictBuffer, options);
|
|
||||||
if (BinaryDictIOUtils.supportsDynamicUpdate(options)) {
|
|
||||||
addressPointer += 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int characters[];
|
|
||||||
if (0 != (flags & FormatSpec.FLAG_HAS_MULTIPLE_CHARS)) {
|
|
||||||
int index = 0;
|
|
||||||
int character = CharEncoding.readChar(dictBuffer);
|
|
||||||
addressPointer += CharEncoding.getCharSize(character);
|
|
||||||
while (-1 != character) {
|
|
||||||
// FusionDictionary is making sure that the length of the word is smaller than
|
|
||||||
// MAX_WORD_LENGTH.
|
|
||||||
// So we'll never write past the end of CHARACTER_BUFFER.
|
|
||||||
CHARACTER_BUFFER[index++] = character;
|
|
||||||
character = CharEncoding.readChar(dictBuffer);
|
|
||||||
addressPointer += CharEncoding.getCharSize(character);
|
|
||||||
}
|
|
||||||
characters = Arrays.copyOfRange(CHARACTER_BUFFER, 0, index);
|
|
||||||
} else {
|
|
||||||
final int character = CharEncoding.readChar(dictBuffer);
|
|
||||||
addressPointer += CharEncoding.getCharSize(character);
|
|
||||||
characters = new int[] { character };
|
|
||||||
}
|
|
||||||
final int frequency;
|
|
||||||
if (0 != (FormatSpec.FLAG_IS_TERMINAL & flags)) {
|
|
||||||
++addressPointer;
|
|
||||||
frequency = dictBuffer.readUnsignedByte();
|
|
||||||
} else {
|
|
||||||
frequency = CharGroup.NOT_A_TERMINAL;
|
|
||||||
}
|
|
||||||
int childrenAddress = readChildrenAddress(dictBuffer, flags, options);
|
|
||||||
if (childrenAddress != FormatSpec.NO_CHILDREN_ADDRESS) {
|
|
||||||
childrenAddress += addressPointer;
|
|
||||||
}
|
|
||||||
addressPointer += BinaryDictIOUtils.getChildrenAddressSize(flags, options);
|
|
||||||
ArrayList<WeightedString> shortcutTargets = null;
|
|
||||||
if (0 != (flags & FormatSpec.FLAG_HAS_SHORTCUT_TARGETS)) {
|
|
||||||
final int pointerBefore = dictBuffer.position();
|
|
||||||
shortcutTargets = new ArrayList<WeightedString>();
|
|
||||||
dictBuffer.readUnsignedShort(); // Skip the size
|
|
||||||
while (true) {
|
|
||||||
final int targetFlags = dictBuffer.readUnsignedByte();
|
|
||||||
final String word = CharEncoding.readString(dictBuffer);
|
|
||||||
shortcutTargets.add(new WeightedString(word,
|
|
||||||
targetFlags & FormatSpec.FLAG_ATTRIBUTE_FREQUENCY));
|
|
||||||
if (0 == (targetFlags & FormatSpec.FLAG_ATTRIBUTE_HAS_NEXT)) break;
|
|
||||||
}
|
|
||||||
addressPointer += dictBuffer.position() - pointerBefore;
|
|
||||||
}
|
|
||||||
ArrayList<PendingAttribute> bigrams = null;
|
|
||||||
if (0 != (flags & FormatSpec.FLAG_HAS_BIGRAMS)) {
|
|
||||||
bigrams = new ArrayList<PendingAttribute>();
|
|
||||||
int bigramCount = 0;
|
|
||||||
while (bigramCount++ < FormatSpec.MAX_BIGRAMS_IN_A_GROUP) {
|
|
||||||
final int bigramFlags = dictBuffer.readUnsignedByte();
|
|
||||||
++addressPointer;
|
|
||||||
final int sign = 0 == (bigramFlags & FormatSpec.FLAG_ATTRIBUTE_OFFSET_NEGATIVE)
|
|
||||||
? 1 : -1;
|
|
||||||
int bigramAddress = addressPointer;
|
|
||||||
switch (bigramFlags & FormatSpec.MASK_ATTRIBUTE_ADDRESS_TYPE) {
|
|
||||||
case FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE:
|
|
||||||
bigramAddress += sign * dictBuffer.readUnsignedByte();
|
|
||||||
addressPointer += 1;
|
|
||||||
break;
|
|
||||||
case FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES:
|
|
||||||
bigramAddress += sign * dictBuffer.readUnsignedShort();
|
|
||||||
addressPointer += 2;
|
|
||||||
break;
|
|
||||||
case FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES:
|
|
||||||
final int offset = (dictBuffer.readUnsignedByte() << 16)
|
|
||||||
+ dictBuffer.readUnsignedShort();
|
|
||||||
bigramAddress += sign * offset;
|
|
||||||
addressPointer += 3;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new RuntimeException("Has bigrams with no address");
|
|
||||||
}
|
|
||||||
bigrams.add(new PendingAttribute(bigramFlags & FormatSpec.FLAG_ATTRIBUTE_FREQUENCY,
|
|
||||||
bigramAddress));
|
|
||||||
if (0 == (bigramFlags & FormatSpec.FLAG_ATTRIBUTE_HAS_NEXT)) break;
|
|
||||||
}
|
|
||||||
if (bigramCount >= FormatSpec.MAX_BIGRAMS_IN_A_GROUP) {
|
|
||||||
MakedictLog.d("too many bigrams in a group.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new CharGroupInfo(originalGroupAddress, addressPointer, flags, characters, frequency,
|
|
||||||
parentAddress, childrenAddress, shortcutTargets, bigrams);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads and returns the char group count out of a buffer and forwards the pointer.
|
* Reads and returns the char group count out of a buffer and forwards the pointer.
|
||||||
*/
|
*/
|
||||||
|
@ -427,24 +336,25 @@ public final class BinaryDictDecoderUtils {
|
||||||
/**
|
/**
|
||||||
* Finds, as a string, the word at the address passed as an argument.
|
* Finds, as a string, the word at the address passed as an argument.
|
||||||
*
|
*
|
||||||
* @param dictBuffer the buffer to read from.
|
* @param dictDecoder the dict decoder.
|
||||||
* @param headerSize the size of the header.
|
* @param headerSize the size of the header.
|
||||||
* @param address the address to seek.
|
* @param address the address to seek.
|
||||||
* @param formatOptions file format options.
|
* @param formatOptions file format options.
|
||||||
* @return the word with its frequency, as a weighted string.
|
* @return the word with its frequency, as a weighted string.
|
||||||
*/
|
*/
|
||||||
/* package for tests */ static WeightedString getWordAtAddress(
|
/* package for tests */ static WeightedString getWordAtAddress(
|
||||||
final DictBuffer dictBuffer, final int headerSize, final int address,
|
final Ver3DictDecoder dictDecoder, final int headerSize, final int address,
|
||||||
final FormatOptions formatOptions) {
|
final FormatOptions formatOptions) {
|
||||||
|
final DictBuffer dictBuffer = dictDecoder.getDictBuffer();
|
||||||
final WeightedString result;
|
final WeightedString result;
|
||||||
final int originalPointer = dictBuffer.position();
|
final int originalPointer = dictBuffer.position();
|
||||||
dictBuffer.position(address);
|
dictBuffer.position(address);
|
||||||
|
|
||||||
if (BinaryDictIOUtils.supportsDynamicUpdate(formatOptions)) {
|
if (BinaryDictIOUtils.supportsDynamicUpdate(formatOptions)) {
|
||||||
result = getWordAtAddressWithParentAddress(dictBuffer, headerSize, address,
|
result = getWordAtAddressWithParentAddress(dictDecoder, headerSize, address,
|
||||||
formatOptions);
|
formatOptions);
|
||||||
} else {
|
} else {
|
||||||
result = getWordAtAddressWithoutParentAddress(dictBuffer, headerSize, address,
|
result = getWordAtAddressWithoutParentAddress(dictDecoder, headerSize, address,
|
||||||
formatOptions);
|
formatOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,8 +364,9 @@ public final class BinaryDictDecoderUtils {
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private static WeightedString getWordAtAddressWithParentAddress(
|
private static WeightedString getWordAtAddressWithParentAddress(
|
||||||
final DictBuffer dictBuffer, final int headerSize, final int address,
|
final Ver3DictDecoder dictDecoder, final int headerSize, final int address,
|
||||||
final FormatOptions options) {
|
final FormatOptions options) {
|
||||||
|
final DictBuffer dictBuffer = dictDecoder.getDictBuffer();
|
||||||
int currentAddress = address;
|
int currentAddress = address;
|
||||||
int frequency = Integer.MIN_VALUE;
|
int frequency = Integer.MIN_VALUE;
|
||||||
final StringBuilder builder = new StringBuilder();
|
final StringBuilder builder = new StringBuilder();
|
||||||
|
@ -465,7 +376,7 @@ public final class BinaryDictDecoderUtils {
|
||||||
int loopCounter = 0;
|
int loopCounter = 0;
|
||||||
do {
|
do {
|
||||||
dictBuffer.position(currentAddress + headerSize);
|
dictBuffer.position(currentAddress + headerSize);
|
||||||
currentInfo = readCharGroup(dictBuffer, currentAddress, options);
|
currentInfo = dictDecoder.readPtNode(currentAddress, options);
|
||||||
if (BinaryDictIOUtils.isMovedGroup(currentInfo.mFlags, options)) {
|
if (BinaryDictIOUtils.isMovedGroup(currentInfo.mFlags, options)) {
|
||||||
currentAddress = currentInfo.mParentAddress + currentInfo.mOriginalAddress;
|
currentAddress = currentInfo.mParentAddress + currentInfo.mOriginalAddress;
|
||||||
}
|
}
|
||||||
|
@ -483,8 +394,9 @@ public final class BinaryDictDecoderUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static WeightedString getWordAtAddressWithoutParentAddress(
|
private static WeightedString getWordAtAddressWithoutParentAddress(
|
||||||
final DictBuffer dictBuffer, final int headerSize, final int address,
|
final Ver3DictDecoder dictDecoder, final int headerSize, final int address,
|
||||||
final FormatOptions options) {
|
final FormatOptions options) {
|
||||||
|
final DictBuffer dictBuffer = dictDecoder.getDictBuffer();
|
||||||
dictBuffer.position(headerSize);
|
dictBuffer.position(headerSize);
|
||||||
final int count = readCharGroupCount(dictBuffer);
|
final int count = readCharGroupCount(dictBuffer);
|
||||||
int groupOffset = BinaryDictIOUtils.getGroupCountSize(count);
|
int groupOffset = BinaryDictIOUtils.getGroupCountSize(count);
|
||||||
|
@ -493,7 +405,7 @@ public final class BinaryDictDecoderUtils {
|
||||||
|
|
||||||
CharGroupInfo last = null;
|
CharGroupInfo last = null;
|
||||||
for (int i = count - 1; i >= 0; --i) {
|
for (int i = count - 1; i >= 0; --i) {
|
||||||
CharGroupInfo info = readCharGroup(dictBuffer, groupOffset, options);
|
CharGroupInfo info = dictDecoder.readPtNode(groupOffset, options);
|
||||||
groupOffset = info.mEndAddress;
|
groupOffset = info.mEndAddress;
|
||||||
if (info.mOriginalAddress == address) {
|
if (info.mOriginalAddress == address) {
|
||||||
builder.append(new String(info.mCharacters, 0, info.mCharacters.length));
|
builder.append(new String(info.mCharacters, 0, info.mCharacters.length));
|
||||||
|
@ -532,17 +444,18 @@ public final class BinaryDictDecoderUtils {
|
||||||
* This will recursively read other node arrays into the structure, populating the reverse
|
* This will recursively read other node arrays into the structure, populating the reverse
|
||||||
* maps on the fly and using them to keep track of already read nodes.
|
* maps on the fly and using them to keep track of already read nodes.
|
||||||
*
|
*
|
||||||
* @param dictBuffer the buffer, correctly positioned at the start of a node array.
|
* @param dictDecoder the dict decoder, correctly positioned at the start of a node array.
|
||||||
* @param headerSize the size, in bytes, of the file header.
|
* @param headerSize the size, in bytes, of the file header.
|
||||||
* @param reverseNodeArrayMap a mapping from addresses to already read node arrays.
|
* @param reverseNodeArrayMap a mapping from addresses to already read node arrays.
|
||||||
* @param reverseGroupMap a mapping from addresses to already read character groups.
|
* @param reverseGroupMap a mapping from addresses to already read character groups.
|
||||||
* @param options file format options.
|
* @param options file format options.
|
||||||
* @return the read node array with all his children already read.
|
* @return the read node array with all his children already read.
|
||||||
*/
|
*/
|
||||||
private static PtNodeArray readNodeArray(final DictBuffer dictBuffer,
|
private static PtNodeArray readNodeArray(final Ver3DictDecoder dictDecoder,
|
||||||
final int headerSize, final Map<Integer, PtNodeArray> reverseNodeArrayMap,
|
final int headerSize, final Map<Integer, PtNodeArray> reverseNodeArrayMap,
|
||||||
final Map<Integer, CharGroup> reverseGroupMap, final FormatOptions options)
|
final Map<Integer, CharGroup> reverseGroupMap, final FormatOptions options)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
final DictBuffer dictBuffer = dictDecoder.getDictBuffer();
|
||||||
final ArrayList<CharGroup> nodeArrayContents = new ArrayList<CharGroup>();
|
final ArrayList<CharGroup> nodeArrayContents = new ArrayList<CharGroup>();
|
||||||
final int nodeArrayOrigin = dictBuffer.position() - headerSize;
|
final int nodeArrayOrigin = dictBuffer.position() - headerSize;
|
||||||
|
|
||||||
|
@ -551,15 +464,15 @@ public final class BinaryDictDecoderUtils {
|
||||||
final int count = readCharGroupCount(dictBuffer);
|
final int count = readCharGroupCount(dictBuffer);
|
||||||
int groupOffset = nodeArrayHeadPosition + BinaryDictIOUtils.getGroupCountSize(count);
|
int groupOffset = nodeArrayHeadPosition + BinaryDictIOUtils.getGroupCountSize(count);
|
||||||
for (int i = count; i > 0; --i) { // Scan the array of CharGroup.
|
for (int i = count; i > 0; --i) { // Scan the array of CharGroup.
|
||||||
CharGroupInfo info = readCharGroup(dictBuffer, groupOffset, options);
|
CharGroupInfo info = dictDecoder.readPtNode(groupOffset, options);
|
||||||
if (BinaryDictIOUtils.isMovedGroup(info.mFlags, options)) continue;
|
if (BinaryDictIOUtils.isMovedGroup(info.mFlags, options)) continue;
|
||||||
ArrayList<WeightedString> shortcutTargets = info.mShortcutTargets;
|
ArrayList<WeightedString> shortcutTargets = info.mShortcutTargets;
|
||||||
ArrayList<WeightedString> bigrams = null;
|
ArrayList<WeightedString> bigrams = null;
|
||||||
if (null != info.mBigrams) {
|
if (null != info.mBigrams) {
|
||||||
bigrams = new ArrayList<WeightedString>();
|
bigrams = new ArrayList<WeightedString>();
|
||||||
for (PendingAttribute bigram : info.mBigrams) {
|
for (PendingAttribute bigram : info.mBigrams) {
|
||||||
final WeightedString word = getWordAtAddress(
|
final WeightedString word = getWordAtAddress(dictDecoder, headerSize,
|
||||||
dictBuffer, headerSize, bigram.mAddress, options);
|
bigram.mAddress, options);
|
||||||
final int reconstructedFrequency =
|
final int reconstructedFrequency =
|
||||||
BinaryDictIOUtils.reconstructBigramFrequency(word.mFrequency,
|
BinaryDictIOUtils.reconstructBigramFrequency(word.mFrequency,
|
||||||
bigram.mFrequency);
|
bigram.mFrequency);
|
||||||
|
@ -571,7 +484,7 @@ public final class BinaryDictDecoderUtils {
|
||||||
if (null == children) {
|
if (null == children) {
|
||||||
final int currentPosition = dictBuffer.position();
|
final int currentPosition = dictBuffer.position();
|
||||||
dictBuffer.position(info.mChildrenAddress + headerSize);
|
dictBuffer.position(info.mChildrenAddress + headerSize);
|
||||||
children = readNodeArray(dictBuffer, headerSize, reverseNodeArrayMap,
|
children = readNodeArray(dictDecoder, headerSize, reverseNodeArrayMap,
|
||||||
reverseGroupMap, options);
|
reverseGroupMap, options);
|
||||||
dictBuffer.position(currentPosition);
|
dictBuffer.position(currentPosition);
|
||||||
}
|
}
|
||||||
|
@ -665,7 +578,7 @@ public final class BinaryDictDecoderUtils {
|
||||||
|
|
||||||
Map<Integer, PtNodeArray> reverseNodeArrayMapping = new TreeMap<Integer, PtNodeArray>();
|
Map<Integer, PtNodeArray> reverseNodeArrayMapping = new TreeMap<Integer, PtNodeArray>();
|
||||||
Map<Integer, CharGroup> reverseGroupMapping = new TreeMap<Integer, CharGroup>();
|
Map<Integer, CharGroup> reverseGroupMapping = new TreeMap<Integer, CharGroup>();
|
||||||
final PtNodeArray root = readNodeArray(dictDecoder.getDictBuffer(), fileHeader.mHeaderSize,
|
final PtNodeArray root = readNodeArray(dictDecoder, fileHeader.mHeaderSize,
|
||||||
reverseNodeArrayMapping, reverseGroupMapping, fileHeader.mFormatOptions);
|
reverseNodeArrayMapping, reverseGroupMapping, fileHeader.mFormatOptions);
|
||||||
|
|
||||||
FusionDictionary newDict = new FusionDictionary(root, fileHeader.mDictionaryOptions);
|
FusionDictionary newDict = new FusionDictionary(root, fileHeader.mDictionaryOptions);
|
||||||
|
|
|
@ -62,10 +62,11 @@ public final class BinaryDictIOUtils {
|
||||||
* Retrieves all node arrays without recursive call.
|
* Retrieves all node arrays without recursive call.
|
||||||
*/
|
*/
|
||||||
private static void readUnigramsAndBigramsBinaryInner(
|
private static void readUnigramsAndBigramsBinaryInner(
|
||||||
final DictBuffer dictBuffer, final int headerSize,
|
final Ver3DictDecoder dictDecoder, final int headerSize,
|
||||||
final Map<Integer, String> words, final Map<Integer, Integer> frequencies,
|
final Map<Integer, String> words, final Map<Integer, Integer> frequencies,
|
||||||
final Map<Integer, ArrayList<PendingAttribute>> bigrams,
|
final Map<Integer, ArrayList<PendingAttribute>> bigrams,
|
||||||
final FormatOptions formatOptions) {
|
final FormatOptions formatOptions) {
|
||||||
|
final DictBuffer dictBuffer = dictDecoder.getDictBuffer();
|
||||||
int[] pushedChars = new int[FormatSpec.MAX_WORD_LENGTH + 1];
|
int[] pushedChars = new int[FormatSpec.MAX_WORD_LENGTH + 1];
|
||||||
|
|
||||||
Stack<Position> stack = new Stack<Position>();
|
Stack<Position> stack = new Stack<Position>();
|
||||||
|
@ -94,8 +95,7 @@ public final class BinaryDictIOUtils {
|
||||||
stack.pop();
|
stack.pop();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
CharGroupInfo info = BinaryDictDecoderUtils.readCharGroup(dictBuffer,
|
CharGroupInfo info = dictDecoder.readPtNode(p.mAddress - headerSize, formatOptions);
|
||||||
p.mAddress - headerSize, formatOptions);
|
|
||||||
for (int i = 0; i < info.mCharacters.length; ++i) {
|
for (int i = 0; i < info.mCharacters.length; ++i) {
|
||||||
pushedChars[index++] = info.mCharacters[i];
|
pushedChars[index++] = info.mCharacters[i];
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,7 @@ public final class BinaryDictIOUtils {
|
||||||
UnsupportedFormatException {
|
UnsupportedFormatException {
|
||||||
// Read header
|
// Read header
|
||||||
final FileHeader header = dictDecoder.readHeader();
|
final FileHeader header = dictDecoder.readHeader();
|
||||||
readUnigramsAndBigramsBinaryInner(dictDecoder.getDictBuffer(), header.mHeaderSize, words,
|
readUnigramsAndBigramsBinaryInner(dictDecoder, header.mHeaderSize, words,
|
||||||
frequencies, bigrams, header.mFormatOptions);
|
frequencies, bigrams, header.mFormatOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,8 +186,8 @@ public final class BinaryDictIOUtils {
|
||||||
boolean foundNextCharGroup = false;
|
boolean foundNextCharGroup = false;
|
||||||
for (int i = 0; i < charGroupCount; ++i) {
|
for (int i = 0; i < charGroupCount; ++i) {
|
||||||
final int charGroupPos = dictBuffer.position();
|
final int charGroupPos = dictBuffer.position();
|
||||||
final CharGroupInfo currentInfo = BinaryDictDecoderUtils.readCharGroup(
|
final CharGroupInfo currentInfo = dictDecoder.readPtNode(charGroupPos,
|
||||||
dictBuffer, dictBuffer.position(), header.mFormatOptions);
|
header.mFormatOptions);
|
||||||
final boolean isMovedGroup = isMovedGroup(currentInfo.mFlags,
|
final boolean isMovedGroup = isMovedGroup(currentInfo.mFlags,
|
||||||
header.mFormatOptions);
|
header.mFormatOptions);
|
||||||
final boolean isDeletedGroup = isDeletedGroup(currentInfo.mFlags,
|
final boolean isDeletedGroup = isDeletedGroup(currentInfo.mFlags,
|
||||||
|
@ -525,8 +525,7 @@ public final class BinaryDictIOUtils {
|
||||||
dictBuffer.position(0);
|
dictBuffer.position(0);
|
||||||
final FileHeader header = dictDecoder.readHeader();
|
final FileHeader header = dictDecoder.readHeader();
|
||||||
dictBuffer.position(position);
|
dictBuffer.position(position);
|
||||||
return BinaryDictDecoderUtils.readCharGroup(dictBuffer, position,
|
return dictDecoder.readPtNode(position, header.mFormatOptions);
|
||||||
header.mFormatOptions);
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package com.android.inputmethod.latin.makedict;
|
||||||
import com.android.inputmethod.annotations.UsedForTesting;
|
import com.android.inputmethod.annotations.UsedForTesting;
|
||||||
import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer;
|
import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer;
|
||||||
import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
|
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.ByteArrayDictBuffer;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -34,6 +35,11 @@ import java.nio.channels.FileChannel;
|
||||||
*/
|
*/
|
||||||
public interface DictDecoder {
|
public interface DictDecoder {
|
||||||
public FileHeader readHeader() throws IOException, UnsupportedFormatException;
|
public FileHeader readHeader() throws IOException, UnsupportedFormatException;
|
||||||
|
/**
|
||||||
|
* Reads a PtNode and returns CharGroupInfo.
|
||||||
|
*/
|
||||||
|
public CharGroupInfo readPtNode(final int originalGroupAddress,
|
||||||
|
final FormatOptions formatOptions);
|
||||||
|
|
||||||
public interface DictionaryBufferFactory {
|
public interface DictionaryBufferFactory {
|
||||||
public DictBuffer getDictionaryBuffer(final File file)
|
public DictBuffer getDictionaryBuffer(final File file)
|
||||||
|
|
|
@ -293,8 +293,8 @@ public final class DynamicBinaryDictIOUtils {
|
||||||
|
|
||||||
for (int i = 0; i < charGroupCount; ++i) {
|
for (int i = 0; i < charGroupCount; ++i) {
|
||||||
address = dictBuffer.position();
|
address = dictBuffer.position();
|
||||||
final CharGroupInfo currentInfo = BinaryDictDecoderUtils.readCharGroup(dictBuffer,
|
final CharGroupInfo currentInfo = dictDecoder.readPtNode(address,
|
||||||
dictBuffer.position(), fileHeader.mFormatOptions);
|
fileHeader.mFormatOptions);
|
||||||
final boolean isMovedGroup = BinaryDictIOUtils.isMovedGroup(currentInfo.mFlags,
|
final boolean isMovedGroup = BinaryDictIOUtils.isMovedGroup(currentInfo.mFlags,
|
||||||
fileHeader.mFormatOptions);
|
fileHeader.mFormatOptions);
|
||||||
if (isMovedGroup) continue;
|
if (isMovedGroup) continue;
|
||||||
|
|
|
@ -21,11 +21,15 @@ import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncodin
|
||||||
import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer;
|
import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer;
|
||||||
import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
|
import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
|
||||||
import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
|
import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
|
||||||
|
import com.android.inputmethod.latin.makedict.FusionDictionary.CharGroup;
|
||||||
|
import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
|
||||||
import com.android.inputmethod.latin.utils.JniUtils;
|
import com.android.inputmethod.latin.utils.JniUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -70,6 +74,96 @@ public class Ver3DictDecoder implements DictDecoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final static class PtNodeReader {
|
||||||
|
protected static int readPtNodeOptionFlags(final DictBuffer dictBuffer) {
|
||||||
|
return dictBuffer.readUnsignedByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static int readParentAddress(final DictBuffer dictBuffer,
|
||||||
|
final FormatOptions formatOptions) {
|
||||||
|
if (BinaryDictIOUtils.supportsDynamicUpdate(formatOptions)) {
|
||||||
|
return BinaryDictDecoderUtils.readSInt24(dictBuffer);
|
||||||
|
} else {
|
||||||
|
return FormatSpec.NO_PARENT_ADDRESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static int readFrequency(final DictBuffer dictBuffer) {
|
||||||
|
return dictBuffer.readUnsignedByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static int readChildrenAddress(final DictBuffer dictBuffer, final int optionFlags,
|
||||||
|
final FormatOptions formatOptions) {
|
||||||
|
if (BinaryDictIOUtils.supportsDynamicUpdate(formatOptions)) {
|
||||||
|
final int address = BinaryDictDecoderUtils.readSInt24(dictBuffer);
|
||||||
|
if (address == 0) return FormatSpec.NO_CHILDREN_ADDRESS;
|
||||||
|
return address;
|
||||||
|
} else {
|
||||||
|
switch (optionFlags & FormatSpec.MASK_GROUP_ADDRESS_TYPE) {
|
||||||
|
case FormatSpec.FLAG_GROUP_ADDRESS_TYPE_ONEBYTE:
|
||||||
|
return dictBuffer.readUnsignedByte();
|
||||||
|
case FormatSpec.FLAG_GROUP_ADDRESS_TYPE_TWOBYTES:
|
||||||
|
return dictBuffer.readUnsignedShort();
|
||||||
|
case FormatSpec.FLAG_GROUP_ADDRESS_TYPE_THREEBYTES:
|
||||||
|
return dictBuffer.readUnsignedInt24();
|
||||||
|
case FormatSpec.FLAG_GROUP_ADDRESS_TYPE_NOADDRESS:
|
||||||
|
default:
|
||||||
|
return FormatSpec.NO_CHILDREN_ADDRESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reads shortcuts and returns the read length.
|
||||||
|
protected static int readShortcut(final DictBuffer dictBuffer,
|
||||||
|
final ArrayList<WeightedString> shortcutTargets) {
|
||||||
|
final int pointerBefore = dictBuffer.position();
|
||||||
|
dictBuffer.readUnsignedShort(); // skip the size
|
||||||
|
while (true) {
|
||||||
|
final int targetFlags = dictBuffer.readUnsignedByte();
|
||||||
|
final String word = CharEncoding.readString(dictBuffer);
|
||||||
|
shortcutTargets.add(new WeightedString(word,
|
||||||
|
targetFlags & FormatSpec.FLAG_ATTRIBUTE_FREQUENCY));
|
||||||
|
if (0 == (targetFlags & FormatSpec.FLAG_ATTRIBUTE_HAS_NEXT)) break;
|
||||||
|
}
|
||||||
|
return dictBuffer.position() - pointerBefore;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static int readBigrams(final DictBuffer dictBuffer,
|
||||||
|
final ArrayList<PendingAttribute> bigrams, final int baseAddress) {
|
||||||
|
int readLength = 0;
|
||||||
|
int bigramCount = 0;
|
||||||
|
while (bigramCount++ < FormatSpec.MAX_BIGRAMS_IN_A_GROUP) {
|
||||||
|
final int bigramFlags = dictBuffer.readUnsignedByte();
|
||||||
|
++readLength;
|
||||||
|
final int sign = 0 == (bigramFlags & FormatSpec.FLAG_ATTRIBUTE_OFFSET_NEGATIVE)
|
||||||
|
? 1 : -1;
|
||||||
|
int bigramAddress = baseAddress + readLength;
|
||||||
|
switch (bigramFlags & FormatSpec.MASK_ATTRIBUTE_ADDRESS_TYPE) {
|
||||||
|
case FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE:
|
||||||
|
bigramAddress += sign * dictBuffer.readUnsignedByte();
|
||||||
|
readLength += 1;
|
||||||
|
break;
|
||||||
|
case FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES:
|
||||||
|
bigramAddress += sign * dictBuffer.readUnsignedShort();
|
||||||
|
readLength += 2;
|
||||||
|
break;
|
||||||
|
case FormatSpec.FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES:
|
||||||
|
final int offset = (dictBuffer.readUnsignedByte() << 16)
|
||||||
|
+ dictBuffer.readUnsignedShort();
|
||||||
|
bigramAddress += sign * offset;
|
||||||
|
readLength += 3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("Has bigrams with no address");
|
||||||
|
}
|
||||||
|
bigrams.add(new PendingAttribute(bigramFlags & FormatSpec.FLAG_ATTRIBUTE_FREQUENCY,
|
||||||
|
bigramAddress));
|
||||||
|
if (0 == (bigramFlags & FormatSpec.FLAG_ATTRIBUTE_HAS_NEXT)) break;
|
||||||
|
}
|
||||||
|
return readLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final File mDictionaryBinaryFile;
|
private final File mDictionaryBinaryFile;
|
||||||
private DictBuffer mDictBuffer;
|
private DictBuffer mDictBuffer;
|
||||||
|
|
||||||
|
@ -116,4 +210,65 @@ public class Ver3DictDecoder implements DictDecoder {
|
||||||
0 != (optionsFlags & FormatSpec.SUPPORTS_DYNAMIC_UPDATE)));
|
0 != (optionsFlags & FormatSpec.SUPPORTS_DYNAMIC_UPDATE)));
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Make this buffer multi thread safe.
|
||||||
|
private final int[] mCharacterBuffer = new int[FormatSpec.MAX_WORD_LENGTH];
|
||||||
|
@Override
|
||||||
|
public CharGroupInfo readPtNode(final int originalGroupAddress,
|
||||||
|
final FormatOptions options) {
|
||||||
|
int addressPointer = originalGroupAddress;
|
||||||
|
final int flags = PtNodeReader.readPtNodeOptionFlags(mDictBuffer);
|
||||||
|
++addressPointer;
|
||||||
|
|
||||||
|
final int parentAddress = PtNodeReader.readParentAddress(mDictBuffer, options);
|
||||||
|
if (BinaryDictIOUtils.supportsDynamicUpdate(options)) {
|
||||||
|
addressPointer += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int characters[];
|
||||||
|
if (0 != (flags & FormatSpec.FLAG_HAS_MULTIPLE_CHARS)) {
|
||||||
|
int index = 0;
|
||||||
|
int character = CharEncoding.readChar(mDictBuffer);
|
||||||
|
addressPointer += CharEncoding.getCharSize(character);
|
||||||
|
while (-1 != character) {
|
||||||
|
// FusionDictionary is making sure that the length of the word is smaller than
|
||||||
|
// MAX_WORD_LENGTH.
|
||||||
|
// So we'll never write past the end of mCharacterBuffer.
|
||||||
|
mCharacterBuffer[index++] = character;
|
||||||
|
character = CharEncoding.readChar(mDictBuffer);
|
||||||
|
addressPointer += CharEncoding.getCharSize(character);
|
||||||
|
}
|
||||||
|
characters = Arrays.copyOfRange(mCharacterBuffer, 0, index);
|
||||||
|
} else {
|
||||||
|
final int character = CharEncoding.readChar(mDictBuffer);
|
||||||
|
addressPointer += CharEncoding.getCharSize(character);
|
||||||
|
characters = new int[] { character };
|
||||||
|
}
|
||||||
|
final int frequency;
|
||||||
|
if (0 != (FormatSpec.FLAG_IS_TERMINAL & flags)) {
|
||||||
|
++addressPointer;
|
||||||
|
frequency = PtNodeReader.readFrequency(mDictBuffer);
|
||||||
|
} else {
|
||||||
|
frequency = CharGroup.NOT_A_TERMINAL;
|
||||||
|
}
|
||||||
|
int childrenAddress = PtNodeReader.readChildrenAddress(mDictBuffer, flags, options);
|
||||||
|
if (childrenAddress != FormatSpec.NO_CHILDREN_ADDRESS) {
|
||||||
|
childrenAddress += addressPointer;
|
||||||
|
}
|
||||||
|
addressPointer += BinaryDictIOUtils.getChildrenAddressSize(flags, options);
|
||||||
|
ArrayList<WeightedString> shortcutTargets = null;
|
||||||
|
if (0 != (flags & FormatSpec.FLAG_HAS_SHORTCUT_TARGETS)) {
|
||||||
|
addressPointer += PtNodeReader.readShortcut(mDictBuffer, shortcutTargets);
|
||||||
|
}
|
||||||
|
ArrayList<PendingAttribute> bigrams = null;
|
||||||
|
if (0 != (flags & FormatSpec.FLAG_HAS_BIGRAMS)) {
|
||||||
|
bigrams = new ArrayList<PendingAttribute>();
|
||||||
|
addressPointer += PtNodeReader.readBigrams(mDictBuffer, bigrams, addressPointer);
|
||||||
|
if (bigrams.size() >= FormatSpec.MAX_BIGRAMS_IN_A_GROUP) {
|
||||||
|
MakedictLog.d("too many bigrams in a group.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new CharGroupInfo(originalGroupAddress, addressPointer, flags, characters, frequency,
|
||||||
|
parentAddress, childrenAddress, shortcutTargets, bigrams);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -512,7 +512,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (fileHeader == null) return null;
|
if (fileHeader == null) return null;
|
||||||
return BinaryDictDecoderUtils.getWordAtAddress(dictBuffer, fileHeader.mHeaderSize,
|
return BinaryDictDecoderUtils.getWordAtAddress(dictDecoder, fileHeader.mHeaderSize,
|
||||||
address - fileHeader.mHeaderSize, fileHeader.mFormatOptions).mWord;
|
address - fileHeader.mHeaderSize, fileHeader.mFormatOptions).mWord;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,14 +112,15 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase {
|
||||||
Log.d(TAG, " end address = " + info.mEndAddress);
|
Log.d(TAG, " end address = " + info.mEndAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void printNode(final DictBuffer dictBuffer,
|
private static void printNode(final Ver3DictDecoder dictDecoder,
|
||||||
final FormatSpec.FormatOptions formatOptions) {
|
final FormatSpec.FormatOptions formatOptions) {
|
||||||
|
final DictBuffer dictBuffer = dictDecoder.getDictBuffer();
|
||||||
Log.d(TAG, "Node at " + dictBuffer.position());
|
Log.d(TAG, "Node at " + dictBuffer.position());
|
||||||
final int count = BinaryDictDecoderUtils.readCharGroupCount(dictBuffer);
|
final int count = BinaryDictDecoderUtils.readCharGroupCount(dictBuffer);
|
||||||
Log.d(TAG, " charGroupCount = " + count);
|
Log.d(TAG, " charGroupCount = " + count);
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
final CharGroupInfo currentInfo = BinaryDictDecoderUtils.readCharGroup(dictBuffer,
|
final CharGroupInfo currentInfo = dictDecoder.readPtNode(dictBuffer.position(),
|
||||||
dictBuffer.position(), formatOptions);
|
formatOptions);
|
||||||
printCharGroup(currentInfo);
|
printCharGroup(currentInfo);
|
||||||
}
|
}
|
||||||
if (formatOptions.mSupportsDynamicUpdate) {
|
if (formatOptions.mSupportsDynamicUpdate) {
|
||||||
|
@ -131,9 +132,9 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase {
|
||||||
private static void printBinaryFile(final Ver3DictDecoder dictDecoder)
|
private static void printBinaryFile(final Ver3DictDecoder dictDecoder)
|
||||||
throws IOException, UnsupportedFormatException {
|
throws IOException, UnsupportedFormatException {
|
||||||
final FileHeader fileHeader = dictDecoder.readHeader();
|
final FileHeader fileHeader = dictDecoder.readHeader();
|
||||||
final DictBuffer buffer = dictDecoder.getDictBuffer();
|
final DictBuffer dictBuffer = dictDecoder.getDictBuffer();
|
||||||
while (buffer.position() < buffer.limit()) {
|
while (dictBuffer.position() < dictBuffer.limit()) {
|
||||||
printNode(buffer, fileHeader.mFormatOptions);
|
printNode(dictDecoder, fileHeader.mFormatOptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,9 +228,8 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase {
|
||||||
new Ver3DictDecoder.DictionaryBufferFromReadOnlyByteBufferFactory());
|
new Ver3DictDecoder.DictionaryBufferFromReadOnlyByteBufferFactory());
|
||||||
final FileHeader fileHeader = dictDecoder.readHeader();
|
final FileHeader fileHeader = dictDecoder.readHeader();
|
||||||
assertEquals(word,
|
assertEquals(word,
|
||||||
BinaryDictDecoderUtils.getWordAtAddress(dictDecoder.getDictBuffer(),
|
BinaryDictDecoderUtils.getWordAtAddress(dictDecoder, fileHeader.mHeaderSize,
|
||||||
fileHeader.mHeaderSize, position - fileHeader.mHeaderSize,
|
position - fileHeader.mHeaderSize, fileHeader.mFormatOptions).mWord);
|
||||||
fileHeader.mFormatOptions).mWord);
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(TAG, "Raised an IOException while looking up a word", e);
|
Log.e(TAG, "Raised an IOException while looking up a word", e);
|
||||||
} catch (UnsupportedFormatException e) {
|
} catch (UnsupportedFormatException e) {
|
||||||
|
|
Loading…
Reference in New Issue