| /* |
| ********************************************************************** |
| * Copyright (c) 2006-2007, Google and others. All Rights Reserved. |
| ********************************************************************** |
| * Author: Mark Davis |
| ********************************************************************** |
| */ |
| package org.unicode.cldr.util; |
| |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.TreeMap; |
| |
| import org.unicode.cldr.util.Dictionary.Matcher; |
| import org.unicode.cldr.util.Dictionary.Matcher.Status; |
| |
| public class DictionaryStringByteConverter extends StringByteConverter { |
| private final Dictionary<String> dictionary; |
| private final Matcher<String> matcher; |
| private final StringByteConverter byteMaker; |
| private final StringBuilder buffer = new StringBuilder(); |
| private final int maxBytesPerChar; |
| private Matcher<CharSequence> backMatcher = null; |
| |
| public Dictionary<String> getDictionary() { |
| return dictionary; |
| } |
| |
| public DictionaryStringByteConverter(Dictionary<String> dictionary, StringByteConverter byteMaker) { |
| super(); |
| this.dictionary = dictionary; |
| matcher = dictionary.getMatcher(); |
| matcher.setText(buffer); |
| this.byteMaker = byteMaker; |
| int mBytesPerChar = 0; |
| for (Iterator<Entry<CharSequence, String>> m = dictionary.getMapping(); m.hasNext();) { |
| Entry<CharSequence, String> entry = m.next(); |
| // System.out.println("** " + key + "\t\t" + value); |
| int bytesPerChar = entry.getValue().length() * byteMaker.getMaxBytesPerChar(); // all bytes are generated |
| // from last char |
| if (mBytesPerChar < bytesPerChar) { |
| mBytesPerChar = bytesPerChar; |
| } |
| } |
| maxBytesPerChar = mBytesPerChar; |
| } |
| |
| @Override |
| public int getMaxBytesPerChar() { |
| return maxBytesPerChar; |
| } |
| |
| @Override |
| public int toBytes(char ch, byte[] output, int bytePosition) { |
| buffer.append(ch); |
| return toBytes(output, bytePosition, true); |
| } |
| |
| @Override |
| public int toBytes(byte[] output, int bytePosition) { |
| return toBytes(output, bytePosition, false); |
| } |
| |
| public int toBytes(byte[] output, int bytePosition, boolean stopOnFinalPartial) { |
| // keep converting until the buffer is empty, or unless we get a PARTIAL at the end |
| while (buffer.length() != 0) { |
| matcher.setText(buffer); // reset the matcher to the start |
| // find last, best status |
| Status status = Status.NONE; |
| int bestEnd = 0; |
| String bestValue = null; |
| main: while (true) { |
| Status tempStatus = matcher.next(); |
| switch (tempStatus) { |
| case NONE: |
| break main; |
| case PARTIAL: |
| // if the partial is at the end, then wait for more input |
| if (stopOnFinalPartial && matcher.getMatchEnd() == buffer.length()) { |
| if (true) matcher.nextUniquePartial(); // for debugging |
| return bytePosition; |
| } |
| continue; // otherwise ignore |
| default: |
| // MATCH |
| status = tempStatus; |
| bestEnd = matcher.getMatchEnd(); |
| bestValue = matcher.getMatchValue(); |
| break; |
| } |
| } |
| // we've now come out, and have either MATCH or not |
| // so replace what we came up with, and continue |
| switch (status) { |
| case MATCH: |
| bytePosition = byteMaker.toBytes(bestValue, output, bytePosition); |
| buffer.delete(0, bestEnd); |
| break; |
| default: |
| bytePosition = byteMaker.toBytes(buffer.charAt(0), output, bytePosition); |
| buffer.delete(0, 1); |
| break; |
| } |
| } |
| return bytePosition; |
| } |
| |
| @Override |
| public Appendable fromBytes(byte[] input, int byteStart, int byteLength, Appendable result) { |
| // first convert from bytes |
| StringBuffer internal = new StringBuffer(); |
| byteMaker.fromBytes(input, byteStart, byteLength, internal); |
| // then convert using dictionary |
| if (backMatcher == null) { |
| Map<CharSequence, CharSequence> back = new TreeMap<CharSequence, CharSequence>( |
| Dictionary.CHAR_SEQUENCE_COMPARATOR); |
| for (Iterator<Entry<CharSequence, String>> m = dictionary.getMapping(); m.hasNext();) { |
| Entry<CharSequence, String> entry = m.next(); |
| if (entry.getValue().length() != 0) { |
| if (!back.containsKey(entry.getValue())) {// may lose info |
| back.put(entry.getValue(), entry.getKey()); |
| } |
| } |
| } |
| backMatcher = new StateDictionaryBuilder<CharSequence>().make(back).getMatcher(); |
| } |
| backMatcher.setText(internal).convert(result); |
| return result; |
| } |
| } |