Move to a parser combinator
.idea/gradle.xml
4 | 4 | <component name="GradleSettings"> | |
5 | 5 | <option name="linkedExternalProjectsSettings"> | |
6 | 6 | <GradleProjectSettings> | |
7 | - | <option name="testRunner" value="PLATFORM" /> | |
7 | + | <option name="testRunner" value="GRADLE" /> | |
8 | 8 | <option name="distributionType" value="DEFAULT_WRAPPED" /> | |
9 | 9 | <option name="externalProjectPath" value="$PROJECT_DIR$" /> | |
10 | 10 | <option name="modules"> | |
… | |||
14 | 14 | <option value="$PROJECT_DIR$/rubytextview" /> | |
15 | 15 | </set> | |
16 | 16 | </option> | |
17 | - | <option name="resolveModulePerSourceSet" value="false" /> | |
18 | 17 | </GradleProjectSettings> | |
19 | 18 | </option> | |
20 | 19 | </component> |
.idea/runConfigurations.xml unknown status 2
1 | - | <?xml version="1.0" encoding="UTF-8"?> | |
2 | - | <project version="4"> | |
3 | - | <component name="RunConfigurationProducerService"> | |
4 | - | <option name="ignoredProducers"> | |
5 | - | <set> | |
6 | - | <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" /> | |
7 | - | <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" /> | |
8 | - | <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" /> | |
9 | - | </set> | |
10 | - | </option> | |
11 | - | </component> | |
12 | - | </project> | |
12 | > | ||
13 | 0 | > | \ No newline at end of file |
app/src/main/java/eu/lepiller/nani/dictionary/DictionaryFactory.java
256 | 256 | for(Dictionary d: dictionaries) { | |
257 | 257 | if (d instanceof ResultDictionary && d.isDownloaded()) { | |
258 | 258 | available++; | |
259 | - | ArrayList<Result> dr = ((ResultDictionary) d).search(text); | |
259 | + | List<Result> dr = ((ResultDictionary) d).search(text); | |
260 | 260 | if(dr != null) { | |
261 | 261 | for(Result r: dr) { | |
262 | 262 | try { |
app/src/main/java/eu/lepiller/nani/dictionary/FileDictionary.java
9 | 9 | import java.io.RandomAccessFile; | |
10 | 10 | import java.util.ArrayList; | |
11 | 11 | import java.util.HashMap; | |
12 | + | import java.util.List; | |
12 | 13 | import java.util.Map; | |
13 | 14 | ||
14 | 15 | public abstract class FileDictionary extends Dictionary { | |
… | |||
31 | 32 | } | |
32 | 33 | } | |
33 | 34 | ||
34 | - | interface TrieValsDecoder<T> { | |
35 | - | T decodeVals(RandomAccessFile file, long pos) throws IOException; | |
36 | - | void skipVals(RandomAccessFile file, long pos) throws IOException; | |
35 | + | static abstract class Parser<T> { | |
36 | + | abstract T parse(RandomAccessFile file) throws IOException; | |
37 | + | } | |
38 | + | ||
39 | + | static abstract class TrieParser<T> { | |
40 | + | protected Parser<T> valParser; | |
41 | + | TrieParser(Parser<T> parser) { | |
42 | + | valParser = parser; | |
43 | + | } | |
44 | + | ||
45 | + | final T decodeVals(RandomAccessFile file, long pos) throws IOException { | |
46 | + | seek(file, pos); | |
47 | + | Log.d(TAG, "if it's a list, it has " + file.readShort() + " elements."); | |
48 | + | seek(file, pos); | |
49 | + | return valParser.parse(file); | |
50 | + | } | |
51 | + | ||
52 | + | void seek(RandomAccessFile file, long pos) throws IOException { | |
53 | + | file.seek(pos); | |
54 | + | } | |
55 | + | ||
56 | + | abstract void skipVals(RandomAccessFile file, long pos) throws IOException; | |
37 | 57 | } | |
38 | 58 | ||
39 | 59 | private final String mUrl; | |
… | |||
142 | 162 | return 0; | |
143 | 163 | } | |
144 | 164 | ||
145 | - | static String getString(RandomAccessFile file) throws IOException { | |
146 | - | byte b; | |
147 | - | ArrayList<Byte> bs = new ArrayList<>(); | |
148 | - | while((b = file.readByte()) != 0) { | |
149 | - | bs.add(b); | |
150 | - | } | |
151 | - | byte[] str = new byte[bs.size()]; | |
152 | - | for(int j=0; j<bs.size(); j++) { | |
153 | - | str[j] = bs.get(j); | |
165 | + | static void logHuffman(Huffman h, ArrayList<Boolean> address) { | |
166 | + | if (h instanceof ResultDictionary.HuffmanValue) { | |
167 | + | Log.v(TAG, "HUFF: " + ((ResultDictionary.HuffmanValue) h).character + " -> " + address.toString()); | |
168 | + | } else if(h instanceof ResultDictionary.HuffmanTree) { | |
169 | + | ArrayList<Boolean> address_l = new ArrayList<>(address); | |
170 | + | address_l.add(false); | |
171 | + | ArrayList<Boolean> address_r = new ArrayList<>(address); | |
172 | + | address_r.add(true); | |
173 | + | logHuffman(((JMDict.HuffmanTree) h).left, address_l); | |
174 | + | logHuffman(((JMDict.HuffmanTree) h).right, address_r); | |
154 | 175 | } | |
155 | - | return new String(str, encoding); | |
156 | 176 | } | |
157 | 177 | ||
158 | - | static ArrayList<String> getStringList(RandomAccessFile file) throws IOException { | |
159 | - | ArrayList<String> results = new ArrayList<>(); | |
160 | - | int number = file.readShort(); | |
161 | - | for(int i=0; i<number; i++) { | |
162 | - | results.add(getString(file)); | |
178 | + | static class StringParser extends Parser<String> { | |
179 | + | @Override | |
180 | + | String parse(RandomAccessFile file) throws IOException { | |
181 | + | byte b; | |
182 | + | ArrayList<Byte> bs = new ArrayList<>(); | |
183 | + | while((b = file.readByte()) != 0) { | |
184 | + | bs.add(b); | |
185 | + | } | |
186 | + | byte[] str = new byte[bs.size()]; | |
187 | + | for(int j=0; j<bs.size(); j++) { | |
188 | + | str[j] = bs.get(j); | |
189 | + | } | |
190 | + | return new String(str, encoding); | |
163 | 191 | } | |
164 | - | return results; | |
165 | 192 | } | |
166 | 193 | ||
167 | - | static ArrayList<Integer> getIntList(RandomAccessFile file) throws IOException { | |
168 | - | ArrayList<Integer> results = new ArrayList<>(); | |
169 | - | int number = file.readShort(); | |
170 | - | for(int i=0; i<number; i++) { | |
171 | - | int tag = (int) file.readShort(); | |
172 | - | results.add(tag); | |
194 | + | static class ListParser<T> extends Parser<List<T>> { | |
195 | + | Parser<T> parser; | |
196 | + | int lenSize; | |
197 | + | ||
198 | + | ListParser(Parser<T> parser) { | |
199 | + | this(2, parser); | |
200 | + | } | |
201 | + | ListParser(int lenSize, Parser<T> parser) { | |
202 | + | this.parser = parser; | |
203 | + | this.lenSize = lenSize; | |
173 | 204 | } | |
174 | - | return results; | |
175 | - | } | |
176 | 205 | ||
177 | - | static Huffman loadHuffman(RandomAccessFile file) throws IOException { | |
178 | - | byte b = file.readByte(); | |
179 | - | if(b == 1) { | |
180 | - | Huffman left = loadHuffman(file); | |
181 | - | Huffman right = loadHuffman(file); | |
182 | - | ||
183 | - | return new HuffmanTree(left, right); | |
184 | - | } else if (b == 0) { | |
185 | - | Log.v(TAG, "Skipping byte " + file.readByte()); | |
186 | - | return new HuffmanValue(""); | |
187 | - | } else { | |
188 | - | ArrayList<Byte> bs = new ArrayList<>(); | |
189 | - | bs.add(b); | |
190 | - | while((b = file.readByte()) != 0) { | |
191 | - | bs.add(b); | |
206 | + | @Override | |
207 | + | List<T> parse(RandomAccessFile file) throws IOException { | |
208 | + | List<T> results = new ArrayList<>(); | |
209 | + | int number; | |
210 | + | switch(lenSize) { | |
211 | + | case 1: | |
212 | + | number = file.readByte(); | |
213 | + | break; | |
214 | + | case 2: | |
215 | + | number = file.readShort(); | |
216 | + | break; | |
217 | + | default: | |
218 | + | number = file.readInt(); | |
192 | 219 | } | |
193 | - | byte[] array = new byte[bs.size()]; | |
194 | - | for(int i=0; i<bs.size(); i++) { | |
195 | - | array[i] = bs.get(i); | |
220 | + | for(int i=0; i<number; i++) { | |
221 | + | Log.d("LISTPARSER", "at position " + file.getFilePointer()); | |
222 | + | results.add(parser.parse(file)); | |
196 | 223 | } | |
197 | - | return new HuffmanValue(new String(array, encoding)); | |
224 | + | return results; | |
198 | 225 | } | |
199 | 226 | } | |
200 | 227 | ||
201 | - | static String getHuffmanString(RandomAccessFile file, Huffman huffman) throws IOException { | |
202 | - | StringBuilder b = new StringBuilder(); | |
203 | - | ArrayList<Boolean> bits = new ArrayList<>(); | |
204 | - | String c = null; | |
205 | - | ResultDictionary.Huffman h = huffman; | |
206 | - | while(c == null || !c.isEmpty()) { | |
207 | - | if(h instanceof ResultDictionary.HuffmanValue) { | |
208 | - | c = ((ResultDictionary.HuffmanValue) h).character; | |
209 | - | //Log.v(TAG, "Huffman read: " + c); | |
210 | - | b.append(c); | |
211 | - | h = huffman; | |
212 | - | } else if(h instanceof ResultDictionary.HuffmanTree) { | |
213 | - | if(bits.isEmpty()) { | |
214 | - | byte by = file.readByte(); | |
215 | - | //Log.v(TAG, "Read byte for huffman: " + by); | |
216 | - | for(int i = 7; i>-1; i--) { | |
217 | - | bits.add((by&(1<<i))!=0); | |
218 | - | } | |
219 | - | //Log.v(TAG, "Read byte for huffman: " + bits); | |
220 | - | } | |
228 | + | static class HuffmanParser extends Parser<Huffman> { | |
229 | + | ||
230 | + | @Override | |
231 | + | Huffman parse(RandomAccessFile file) throws IOException { | |
232 | + | byte b = file.readByte(); | |
233 | + | if(b == 1) { | |
234 | + | Huffman left = new HuffmanParser().parse(file); | |
235 | + | Huffman right = new HuffmanParser().parse(file); | |
221 | 236 | ||
222 | - | Boolean bo = bits.get(0); | |
223 | - | bits.remove(0); | |
224 | - | h = bo? ((ResultDictionary.HuffmanTree) h).right: ((ResultDictionary.HuffmanTree) h).left; | |
237 | + | return new HuffmanTree(left, right); | |
238 | + | } else if (b == 0) { | |
239 | + | Log.v(TAG, "Skipping byte " + file.readByte()); | |
240 | + | return new HuffmanValue(""); | |
241 | + | } else { | |
242 | + | ArrayList<Byte> bs = new ArrayList<>(); | |
243 | + | bs.add(b); | |
244 | + | while((b = file.readByte()) != 0) { | |
245 | + | bs.add(b); | |
246 | + | } | |
247 | + | byte[] array = new byte[bs.size()]; | |
248 | + | for(int i=0; i<bs.size(); i++) { | |
249 | + | array[i] = bs.get(i); | |
250 | + | } | |
251 | + | return new HuffmanValue(new String(array, encoding)); | |
225 | 252 | } | |
226 | 253 | } | |
227 | - | ||
228 | - | return b.toString(); | |
229 | 254 | } | |
230 | 255 | ||
231 | - | static void logHuffman(Huffman h, ArrayList<Boolean> address) { | |
232 | - | if (h instanceof ResultDictionary.HuffmanValue) { | |
233 | - | Log.v(TAG, "HUFF: " + ((ResultDictionary.HuffmanValue) h).character + " -> " + address.toString()); | |
234 | - | } else if(h instanceof ResultDictionary.HuffmanTree) { | |
235 | - | ArrayList<Boolean> address_l = new ArrayList<>(address); | |
236 | - | address_l.add(false); | |
237 | - | ArrayList<Boolean> address_r = new ArrayList<>(address); | |
238 | - | address_r.add(true); | |
239 | - | logHuffman(((JMDict.HuffmanTree) h).left, address_l); | |
240 | - | logHuffman(((JMDict.HuffmanTree) h).right, address_r); | |
256 | + | static class HuffmanStringParser extends Parser<String> { | |
257 | + | Huffman huffman; | |
258 | + | HuffmanStringParser(Huffman huffman) { | |
259 | + | this.huffman = huffman; | |
241 | 260 | } | |
242 | - | } | |
243 | 261 | ||
244 | - | static ArrayList<String> getHuffmanStringList(RandomAccessFile file, Huffman huffman) throws IOException { | |
245 | - | ArrayList<String> results = new ArrayList<>(); | |
246 | - | int number = file.readShort(); | |
247 | - | Log.v(TAG, "huffmanStrings: " + number); | |
248 | - | for(int i=0; i<number; i++) { | |
249 | - | results.add(getHuffmanString(file, huffman)); | |
262 | + | @Override | |
263 | + | String parse(RandomAccessFile file) throws IOException { | |
264 | + | StringBuilder b = new StringBuilder(); | |
265 | + | ArrayList<Boolean> bits = new ArrayList<>(); | |
266 | + | String c = null; | |
267 | + | ResultDictionary.Huffman h = huffman; | |
268 | + | while(c == null || !c.isEmpty()) { | |
269 | + | if(h instanceof ResultDictionary.HuffmanValue) { | |
270 | + | c = ((ResultDictionary.HuffmanValue) h).character; | |
271 | + | //Log.v(TAG, "Huffman read: " + c); | |
272 | + | b.append(c); | |
273 | + | h = huffman; | |
274 | + | } else if(h instanceof ResultDictionary.HuffmanTree) { | |
275 | + | if(bits.isEmpty()) { | |
276 | + | byte by = file.readByte(); | |
277 | + | //Log.v(TAG, "Read byte for huffman: " + by); | |
278 | + | for(int i = 7; i>-1; i--) { | |
279 | + | bits.add((by&(1<<i))!=0); | |
280 | + | } | |
281 | + | //Log.v(TAG, "Read byte for huffman: " + bits); | |
282 | + | } | |
283 | + | ||
284 | + | Boolean bo = bits.get(0); | |
285 | + | bits.remove(0); | |
286 | + | h = bo? ((ResultDictionary.HuffmanTree) h).right: ((ResultDictionary.HuffmanTree) h).left; | |
287 | + | } | |
288 | + | } | |
289 | + | ||
290 | + | return b.toString(); | |
250 | 291 | } | |
251 | - | return results; | |
252 | 292 | } | |
253 | 293 | ||
254 | - | static<T> T searchTrie(RandomAccessFile file, long triePos, byte[] txt, TrieValsDecoder<T> decoder) throws IOException { | |
294 | + | static<T> T searchTrie(RandomAccessFile file, long triePos, byte[] txt, TrieParser<T> decoder) throws IOException { | |
255 | 295 | file.seek(triePos); | |
256 | 296 | if(txt.length == 0) { | |
257 | 297 | Log.v(TAG, "found trie value, reading values"); |
app/src/main/java/eu/lepiller/nani/dictionary/KanjiDict.java
33 | 33 | return R.drawable.ic_nani_edrdg; | |
34 | 34 | } | |
35 | 35 | ||
36 | - | KanjiResult getValue(RandomAccessFile file, long pos, String kanji) throws IOException { | |
37 | - | Log.d(TAG, "getValue at " + pos); | |
38 | - | file.seek(pos); | |
39 | - | int stroke = file.readByte(); | |
40 | - | Log.d(TAG, "strokes: " + stroke); | |
41 | - | ||
42 | - | List<String> senses = getHuffmanStringList(file, meaningHuffman); | |
43 | - | List<KanjiResult.Sense> meanings = new ArrayList<>(); | |
44 | - | for(String s: senses) { | |
45 | - | meanings.add(new KanjiResult.Sense(this.getLang(), s)); | |
36 | + | class ResultParser extends Parser<KanjiResult> { | |
37 | + | String kanji; | |
38 | + | ResultParser(String kanji) { | |
39 | + | this.kanji = kanji; | |
46 | 40 | } | |
47 | - | List<String> kun = getHuffmanStringList(file, readingHuffman); | |
48 | - | List<String> on = getHuffmanStringList(file, readingHuffman); | |
49 | - | List<String> nanori = getHuffmanStringList(file, readingHuffman); | |
50 | 41 | ||
51 | - | return new KanjiResult(kanji, stroke, meanings, kun, on, nanori, null, null); | |
42 | + | @Override | |
43 | + | KanjiResult parse(RandomAccessFile file) throws IOException { | |
44 | + | int stroke = file.readByte(); | |
45 | + | Log.d(TAG, "strokes: " + stroke); | |
46 | + | ||
47 | + | List<String> senses = new ListParser<>(new HuffmanStringParser(meaningHuffman)).parse(file); | |
48 | + | List<KanjiResult.Sense> meanings = new ArrayList<>(); | |
49 | + | for(String s: senses) { | |
50 | + | meanings.add(new KanjiResult.Sense(KanjiDict.this.getLang(), s)); | |
51 | + | } | |
52 | + | List<String> kun = new ListParser<>(new HuffmanStringParser(readingHuffman)).parse(file); | |
53 | + | List<String> on = new ListParser<>(new HuffmanStringParser(readingHuffman)).parse(file); | |
54 | + | List<String> nanori = new ListParser<>(new HuffmanStringParser(readingHuffman)).parse(file); | |
55 | + | ||
56 | + | return new KanjiResult(kanji, stroke, meanings, kun, on, nanori, null, null); | |
57 | + | } | |
52 | 58 | } | |
53 | 59 | ||
54 | 60 | @Override | |
… | |||
82 | 88 | ||
83 | 89 | byte[] search = kanji.toLowerCase().getBytes(); | |
84 | 90 | file.skipBytes(4); // size | |
85 | - | meaningHuffman = loadHuffman(file); | |
86 | - | readingHuffman = loadHuffman(file); | |
91 | + | meaningHuffman = new HuffmanParser().parse(file); | |
92 | + | readingHuffman = new HuffmanParser().parse(file); | |
87 | 93 | long kanjiTriePos = file.getFilePointer(); | |
88 | 94 | ||
89 | 95 | Log.d(TAG, "trie pos: " + kanjiTriePos); | |
90 | 96 | ||
91 | - | return searchTrie(file, kanjiTriePos, search, new TrieValsDecoder<KanjiResult>() { | |
97 | + | return searchTrie(file, kanjiTriePos, search, new TrieParser<KanjiResult>(new ResultParser(kanji)) { | |
92 | 98 | @Override | |
93 | - | public KanjiResult decodeVals(RandomAccessFile file1, long pos) throws IOException { | |
94 | - | Log.d(TAG, "decoding val"); | |
99 | + | public void skipVals(RandomAccessFile file1, long pos) throws IOException { | |
95 | 100 | file1.seek(pos); | |
96 | - | return getValue(file1, file1.readInt(), kanji); | |
101 | + | file1.skipBytes(4); | |
97 | 102 | } | |
98 | 103 | ||
99 | 104 | @Override | |
100 | - | public void skipVals(RandomAccessFile file1, long pos) throws IOException { | |
101 | - | file1.seek(pos); | |
102 | - | file1.skipBytes(4); | |
105 | + | void seek(RandomAccessFile file, long pos) throws IOException { | |
106 | + | file.seek(pos); | |
107 | + | file.seek(file.readInt()); | |
103 | 108 | } | |
104 | 109 | }); | |
105 | 110 | } catch (FileNotFoundException e) { |
app/src/main/java/eu/lepiller/nani/dictionary/KanjiVG.java
65 | 65 | ||
66 | 66 | byte[] search = kanji.toLowerCase().getBytes(); | |
67 | 67 | file.skipBytes(4); // size | |
68 | - | commandHuffman = loadHuffman(file); | |
68 | + | commandHuffman = new HuffmanParser().parse(file); | |
69 | 69 | long kanjiTriePos = file.getFilePointer(); | |
70 | 70 | ||
71 | 71 | Log.d(TAG, "trie pos: " + kanjiTriePos); | |
72 | 72 | ||
73 | - | return searchTrie(file, kanjiTriePos, search, new TrieValsDecoder<KanjiResult>() { | |
73 | + | return searchTrie(file, kanjiTriePos, search, new TrieParser<KanjiResult>(new ResultParser(kanji)) { | |
74 | 74 | @Override | |
75 | - | public KanjiResult decodeVals(RandomAccessFile file1, long pos) throws IOException { | |
76 | - | Log.d(TAG, "decoding val"); | |
75 | + | public void skipVals(RandomAccessFile file1, long pos) throws IOException { | |
77 | 76 | file1.seek(pos); | |
78 | - | return getValue(file1, file1.readInt(), kanji); | |
77 | + | file1.skipBytes(4); | |
79 | 78 | } | |
80 | 79 | ||
81 | 80 | @Override | |
82 | - | public void skipVals(RandomAccessFile file1, long pos) throws IOException { | |
83 | - | file1.seek(pos); | |
84 | - | file1.skipBytes(4); | |
81 | + | void seek(RandomAccessFile file, long pos) throws IOException { | |
82 | + | file.seek(pos); | |
83 | + | file.seek(file.readInt()); | |
85 | 84 | } | |
86 | 85 | }); | |
87 | 86 | } catch (FileNotFoundException e) { | |
… | |||
241 | 240 | } | |
242 | 241 | } | |
243 | 242 | ||
244 | - | KanjiResult.Stroke getStroke(RandomAccessFile file) throws IOException { | |
245 | - | String command = getHuffmanString(file, commandHuffman); | |
246 | - | String x = getHuffmanString(file, commandHuffman); | |
247 | - | String y = getHuffmanString(file, commandHuffman); | |
243 | + | class StrokeParser extends Parser<KanjiResult.Stroke> { | |
244 | + | @Override | |
245 | + | KanjiResult.Stroke parse(RandomAccessFile file) throws IOException { | |
246 | + | String command = new HuffmanStringParser(commandHuffman).parse(file); | |
247 | + | String x = new HuffmanStringParser(commandHuffman).parse(file); | |
248 | + | String y = new HuffmanStringParser(commandHuffman).parse(file); | |
248 | 249 | ||
249 | - | Path path = new Path(); | |
250 | + | Path path = new Path(); | |
250 | 251 | ||
251 | - | try { | |
252 | - | parsePath(path, command); | |
253 | - | } catch (ParseException e) { | |
254 | - | e.printStackTrace(); | |
255 | - | path.reset(); | |
256 | - | } | |
252 | + | try { | |
253 | + | parsePath(path, command); | |
254 | + | } catch (ParseException e) { | |
255 | + | e.printStackTrace(); | |
256 | + | path.reset(); | |
257 | + | } | |
257 | 258 | ||
258 | - | return new KanjiResult.Stroke(path, 109, Float.parseFloat(x), Float.parseFloat(y)); | |
259 | + | return new KanjiResult.Stroke(path, 109, Float.parseFloat(x), Float.parseFloat(y)); | |
260 | + | } | |
259 | 261 | } | |
260 | 262 | ||
261 | - | KanjiResult getValue(RandomAccessFile file, long pos, String kanji) throws IOException { | |
262 | - | Log.d(TAG, "getValue at " + pos); | |
263 | - | file.seek(pos); | |
264 | - | ||
265 | - | List<String> elements = getStringList(file); | |
266 | - | List<KanjiResult.Stroke> strokes = new ArrayList<>(); | |
267 | - | int number = file.readShort(); | |
268 | - | for(int i=0; i<number; i++) { | |
269 | - | strokes.add(getStroke(file)); | |
263 | + | class ResultParser extends Parser<KanjiResult> { | |
264 | + | String kanji; | |
265 | + | ResultParser(String kanji) { | |
266 | + | this.kanji = kanji; | |
270 | 267 | } | |
268 | + | @Override | |
269 | + | KanjiResult parse(RandomAccessFile file) throws IOException { | |
270 | + | List<String> elements = new ListParser<>(new StringParser()).parse(file); | |
271 | + | List<KanjiResult.Stroke> strokes = new ListParser<>(new StrokeParser()).parse(file); | |
271 | 272 | ||
272 | - | return new KanjiResult(kanji, -1, null, null, null, null, elements, strokes); | |
273 | + | return new KanjiResult(kanji, -1, null, null, null, null, elements, strokes); | |
274 | + | } | |
273 | 275 | } | |
274 | 276 | } |
app/src/main/java/eu/lepiller/nani/dictionary/RadicalDict.java
38 | 38 | private void fillStrokeCount(RandomAccessFile file) throws IOException{ | |
39 | 39 | int size = file.readShort(); | |
40 | 40 | for(int i=0; i<size; i++) { | |
41 | - | String kanji = getString(file); | |
41 | + | String kanji = new StringParser().parse(file); | |
42 | 42 | int stroke = file.readByte(); | |
43 | 43 | strokeCount.put(kanji, stroke); | |
44 | 44 | } | |
… | |||
47 | 47 | private void fillRadicalStrokeCount(RandomAccessFile file) throws IOException { | |
48 | 48 | int size = file.readShort(); | |
49 | 49 | for(int i=0; i<size; i++) { | |
50 | - | String radical = getString(file); | |
50 | + | String radical = new StringParser().parse(file); | |
51 | 51 | int stroke = file.readByte(); | |
52 | 52 | ||
53 | 53 | radicalStrokeCount.put(radical, stroke); | |
… | |||
57 | 57 | private void fillRadicals(RandomAccessFile file) throws IOException { | |
58 | 58 | int size = file.readShort(); | |
59 | 59 | for(int i=0; i<size; i++) { | |
60 | - | String radical = getString(file); | |
61 | - | String kanji = getString(file); | |
60 | + | String radical = new StringParser().parse(file); | |
61 | + | String kanji = new StringParser().parse(file); | |
62 | 62 | List<String> lst = new ArrayList<>(); | |
63 | 63 | for(String s: kanji.split("")) { | |
64 | 64 | if(s.compareTo("") != 0) { |
app/src/main/java/eu/lepiller/nani/dictionary/ResultDictionary.java
9 | 9 | import java.util.ArrayList; | |
10 | 10 | import java.util.Arrays; | |
11 | 11 | import java.util.Collections; | |
12 | + | import java.util.List; | |
12 | 13 | ||
13 | 14 | import eu.lepiller.nani.result.Result; | |
14 | 15 | ||
… | |||
29 | 30 | meaningHuffman = null; | |
30 | 31 | } | |
31 | 32 | ||
32 | - | private Result getValue(RandomAccessFile file, long pos) throws IOException { | |
33 | - | file.seek(pos); | |
34 | - | Log.v(TAG, "Getting value at " + pos); | |
35 | - | ArrayList<String> kanjis = getHuffmanStringList(file, kanjiHuffman); | |
36 | - | ||
37 | - | Log.v(TAG, "Getting readings"); | |
38 | - | ArrayList<Result.Reading> readings = new ArrayList<>(); | |
39 | - | int reading_number = file.readShort(); | |
40 | - | Log.v(TAG, reading_number + " readings."); | |
41 | - | for(int i=0; i<reading_number; i++) { | |
42 | - | ArrayList<String> reading_kanjis = getStringList(file); | |
33 | + | class ReadingParser extends Parser<Result.Reading> { | |
34 | + | @Override | |
35 | + | Result.Reading parse(RandomAccessFile file) throws IOException { | |
36 | + | List<String> reading_kanjis = new ListParser<>(new StringParser()).parse(file); | |
43 | 37 | Log.v(TAG, "kanjis: " + reading_kanjis); | |
44 | - | ArrayList<String> reading_infos = getStringList(file); | |
38 | + | List<String> reading_infos = new ListParser<>(new StringParser()).parse(file); | |
45 | 39 | Log.v(TAG, "infos: " + reading_kanjis); | |
46 | - | ArrayList<String> reading_readings = getHuffmanStringList(file, readingHuffman); | |
47 | - | Result.Reading r = new Result.Reading(reading_kanjis, reading_infos, reading_readings); | |
48 | - | readings.add(r); | |
40 | + | List<String> reading_readings = new ListParser<>(new HuffmanStringParser(readingHuffman)).parse(file); | |
41 | + | return new Result.Reading(reading_kanjis, reading_infos, reading_readings); | |
49 | 42 | } | |
43 | + | } | |
50 | 44 | ||
51 | - | ArrayList<Result.Sense> senses = new ArrayList<>(); | |
52 | - | int meaning_number = file.readShort(); | |
53 | - | Log.v(TAG, meaning_number + " meanings."); | |
54 | - | for(int i=0; i<meaning_number; i++) { | |
55 | - | ArrayList<String> sense_references = getStringList(file); | |
56 | - | ArrayList<String> sense_limits = getStringList(file); | |
57 | - | ArrayList<Result.Source> sense_sources = new ArrayList<>(); | |
58 | - | int source_number = file.readShort(); | |
59 | - | for(int j=0; j<source_number; j++) { | |
60 | - | ArrayList<String> source_content = getStringList(file); | |
61 | - | boolean source_wasei = file.read() != 0; | |
62 | - | String source_language = getString(file); | |
63 | - | sense_sources.add(new Result.Source(source_content, source_wasei, source_language)); | |
64 | - | } | |
65 | - | ArrayList<String> sense_infos = getHuffmanStringList(file, meaningHuffman); | |
66 | - | ArrayList<String> sense_glosses = getHuffmanStringList(file, meaningHuffman); | |
67 | - | String sense_language = getString(file); | |
68 | - | senses.add(new Result.Sense(sense_references, sense_limits, sense_infos, sense_sources, | |
69 | - | sense_glosses, sense_language)); | |
45 | + | static class SourceParser extends Parser<Result.Source> { | |
46 | + | @Override | |
47 | + | Result.Source parse(RandomAccessFile file) throws IOException { | |
48 | + | List<String> source_content = new ListParser<>(new StringParser()).parse(file); | |
49 | + | boolean source_wasei = file.read() != 0; | |
50 | + | String source_language = new StringParser().parse(file); | |
51 | + | return new Result.Source(source_content, source_wasei, source_language); | |
70 | 52 | } | |
53 | + | } | |
71 | 54 | ||
72 | - | int score = file.readChar(); | |
73 | - | return new Result(kanjis, readings, senses, score); | |
55 | + | class SenseParser extends Parser<Result.Sense> { | |
56 | + | @Override | |
57 | + | Result.Sense parse(RandomAccessFile file) throws IOException { | |
58 | + | List<String> sense_references = new ListParser<>(new StringParser()).parse(file); | |
59 | + | List<String> sense_limits = new ListParser<>(new StringParser()).parse(file); | |
60 | + | List<Result.Source> sense_sources = new ListParser<>(new SourceParser()).parse(file); | |
61 | + | List<String> sense_infos = new ListParser<>(new HuffmanStringParser(meaningHuffman)).parse(file); | |
62 | + | List<String> sense_glosses = new ListParser<>(new HuffmanStringParser(meaningHuffman)).parse(file); | |
63 | + | String sense_language = new StringParser().parse(file); | |
64 | + | return new Result.Sense(sense_references, sense_limits, sense_infos, sense_sources, | |
65 | + | sense_glosses, sense_language); | |
66 | + | } | |
74 | 67 | } | |
75 | 68 | ||
76 | - | private ArrayList<Integer> getValues(RandomAccessFile file, long triePos) throws IOException { | |
77 | - | file.seek(triePos); | |
78 | - | Log.v(TAG, "Getting values"); | |
79 | - | int valuesLength = file.readShort(); | |
80 | - | ArrayList<Integer> results = new ArrayList<>(); | |
81 | - | ArrayList<Integer> exactResults = new ArrayList<>(); | |
69 | + | class ResultParser extends Parser<Result> { | |
70 | + | @Override | |
71 | + | Result parse(RandomAccessFile file) throws IOException { | |
72 | + | List<String> kanjis = new ListParser<>(new HuffmanStringParser(kanjiHuffman)).parse(file); | |
82 | 73 | ||
83 | - | Log.v(TAG, "Number of values: " + valuesLength); | |
84 | - | for(int i=0; i<valuesLength; i++) { | |
85 | - | exactResults.add(file.readInt()); | |
86 | - | } | |
74 | + | Log.v(TAG, "Getting readings"); | |
75 | + | List<Result.Reading> readings = new ListParser<>(new ReadingParser()).parse(file); | |
87 | 76 | ||
88 | - | int transitionLength = file.readByte(); | |
89 | - | Log.v(TAG, "Number of transitions: " + transitionLength); | |
90 | - | int[] others = new int[transitionLength]; | |
91 | - | for(int i=0; i<transitionLength; i++) { | |
92 | - | file.skipBytes(1); | |
93 | - | others[i] = file.readInt(); | |
94 | - | } | |
77 | + | List<Result.Sense> senses = new ListParser<>(new SenseParser()).parse(file); | |
95 | 78 | ||
96 | - | for(int i=0; i<transitionLength; i++) { | |
97 | - | results.addAll(getValues(file, others[i])); | |
79 | + | int score = file.readChar(); | |
80 | + | return new Result(kanjis, readings, senses, score); | |
98 | 81 | } | |
82 | + | } | |
99 | 83 | ||
100 | - | Collections.sort(results); | |
101 | - | Collections.sort(exactResults); | |
84 | + | static class ValuesParser extends Parser<List<Integer>> { | |
85 | + | @Override | |
86 | + | List<Integer> parse(RandomAccessFile file) throws IOException { | |
87 | + | ArrayList<Integer> results = new ArrayList<>(); | |
102 | 88 | ||
103 | - | Log.v(TAG, "exact result size: " + exactResults.size() + ", result size: " + results.size()); | |
104 | - | Log.v(TAG, "exact: " + Arrays.toString(exactResults.toArray()) + ", others: " + Arrays.toString(results.toArray())); | |
105 | - | exactResults.addAll(results); | |
106 | - | return exactResults; | |
107 | - | } | |
89 | + | Log.v(TAG, "Getting values"); | |
90 | + | List<Integer> exactResults = new ListParser<>(new Parser<Integer>() { | |
91 | + | @Override | |
92 | + | Integer parse(RandomAccessFile file) throws IOException { | |
93 | + | return file.readInt(); | |
94 | + | } | |
95 | + | }).parse(file); | |
108 | 96 | ||
109 | - | private ArrayList<Integer> searchTrie(RandomAccessFile file, long triePos, byte[] txt) throws IOException { | |
110 | - | return searchTrie(file, triePos, txt, new TrieValsDecoder<ArrayList<Integer>>() { | |
111 | - | @Override | |
112 | - | public ArrayList<Integer> decodeVals(RandomAccessFile file, long pos) throws IOException { | |
113 | - | return getValues(file, pos); | |
97 | + | List<Integer> others = new ListParser<>(1, new Parser<Integer>() { | |
98 | + | @Override | |
99 | + | Integer parse(RandomAccessFile file) throws IOException { | |
100 | + | file.skipBytes(1); | |
101 | + | return file.readInt(); | |
102 | + | } | |
103 | + | }).parse(file); | |
104 | + | ||
105 | + | for(Integer pos: others) { | |
106 | + | file.seek(pos); | |
107 | + | results.addAll(new ValuesParser().parse(file)); | |
114 | 108 | } | |
115 | 109 | ||
110 | + | Collections.sort(results); | |
111 | + | Collections.sort(exactResults); | |
112 | + | ||
113 | + | Log.v(TAG, "exact result size: " + exactResults.size() + ", result size: " + results.size()); | |
114 | + | Log.v(TAG, "exact: " + Arrays.toString(exactResults.toArray()) + ", others: " + Arrays.toString(results.toArray())); | |
115 | + | exactResults.addAll(results); | |
116 | + | return exactResults; | |
117 | + | } | |
118 | + | } | |
119 | + | ||
120 | + | private List<Integer> searchTrie(RandomAccessFile file, long triePos, byte[] txt) throws IOException { | |
121 | + | return searchTrie(file, triePos, txt, new TrieParser<List<Integer>>(new ValuesParser()) { | |
116 | 122 | @Override | |
117 | 123 | public void skipVals(RandomAccessFile file, long pos) throws IOException { | |
118 | 124 | file.seek(pos); | |
… | |||
123 | 129 | }); | |
124 | 130 | } | |
125 | 131 | ||
126 | - | ArrayList<Result> search(String text) throws IncompatibleFormatException { | |
132 | + | List<Result> search(String text) throws IncompatibleFormatException { | |
127 | 133 | if (isDownloaded()) { | |
128 | 134 | try { | |
129 | 135 | RandomAccessFile file = new RandomAccessFile(getFile(), "r"); | |
… | |||
160 | 166 | Log.v(TAG, "reading: " + readingTriePos); | |
161 | 167 | Log.v(TAG, "meaning: " + meaningTriePos); | |
162 | 168 | ||
163 | - | kanjiHuffman = loadHuffman(file); | |
164 | - | readingHuffman = loadHuffman(file); | |
165 | - | meaningHuffman = loadHuffman(file); | |
169 | + | kanjiHuffman = new HuffmanParser().parse(file); | |
170 | + | readingHuffman = new HuffmanParser().parse(file); | |
171 | + | meaningHuffman = new HuffmanParser().parse(file); | |
166 | 172 | ||
167 | 173 | logHuffman(readingHuffman, new ArrayList<>()); | |
168 | 174 | ||
169 | 175 | // Search in Japanese, by kanji and reading | |
170 | 176 | Log.d(TAG, "search: by kanji and reading"); | |
171 | - | ArrayList<Integer> results = searchTrie(file, kanjiTriePos, search); | |
172 | - | ArrayList<Integer> readingResults = searchTrie(file, readingTriePos, search); | |
177 | + | List<Integer> results = searchTrie(file, kanjiTriePos, search); | |
178 | + | List<Integer> readingResults = searchTrie(file, readingTriePos, search); | |
173 | 179 | if(results != null && readingResults != null) | |
174 | 180 | results.addAll(readingResults); | |
175 | 181 | else if (results == null) | |
… | |||
185 | 191 | ||
186 | 192 | Log.d(TAG, results.size() + " result(s)"); | |
187 | 193 | ||
188 | - | ArrayList<Result> r = new ArrayList<>(); | |
189 | - | ArrayList<Integer> uniqResults = new ArrayList<>(); | |
194 | + | List<Result> r = new ArrayList<>(); | |
195 | + | List<Integer> uniqResults = new ArrayList<>(); | |
190 | 196 | for(Integer i: results) { | |
191 | 197 | if(!uniqResults.contains(i)) | |
192 | 198 | uniqResults.add(i); | |
… | |||
195 | 201 | Log.v(TAG, Arrays.toString(uniqResults.toArray())); | |
196 | 202 | ||
197 | 203 | int num = 0; | |
198 | - | for(int i: uniqResults) { | |
204 | + | for(int pos: uniqResults) { | |
199 | 205 | if(num > 10) | |
200 | 206 | break; | |
201 | 207 | num++; | |
202 | - | r.add(getValue(file, i)); | |
208 | + | file.seek(pos); | |
209 | + | r.add(new ResultParser().parse(file)); | |
203 | 210 | } | |
204 | 211 | return r; | |
205 | 212 | } catch (FileNotFoundException e) { |
app/src/main/java/eu/lepiller/nani/dictionary/WadokuPitchDictionary.java
29 | 29 | ||
30 | 30 | private String findPitch(String kanji, String reading, RandomAccessFile file) throws IOException { | |
31 | 31 | String concat = kanji + reading; | |
32 | - | return searchTrie(file, triePos, concat.getBytes(), new TrieValsDecoder<String>() { | |
33 | - | @Override | |
34 | - | public String decodeVals(RandomAccessFile file, long pos) throws IOException { | |
35 | - | file.seek(pos); | |
36 | - | Log.d(TAG, "decoding at " + pos); | |
37 | - | return getHuffmanString(file, huffman); | |
38 | - | } | |
39 | - | ||
32 | + | return searchTrie(file, triePos, concat.getBytes(), new TrieParser<String>(new HuffmanStringParser(huffman)) { | |
40 | 33 | @Override | |
41 | 34 | public void skipVals(RandomAccessFile file, long pos) throws IOException { | |
42 | 35 | file.seek(pos); | |
43 | - | getHuffmanString(file, huffman); | |
36 | + | new HuffmanStringParser(huffman).parse(file); | |
44 | 37 | } | |
45 | 38 | }); | |
46 | 39 | } | |
… | |||
62 | 55 | // number of entries | |
63 | 56 | file.readInt(); | |
64 | 57 | ||
65 | - | huffman = loadHuffman(file); | |
58 | + | huffman = new HuffmanParser().parse(file); | |
66 | 59 | logHuffman(huffman, new ArrayList<>()); | |
67 | 60 | ||
68 | 61 | triePos = file.getFilePointer(); |
app/src/main/java/eu/lepiller/nani/result/Result.java
14 | 14 | ||
15 | 15 | public class Result { | |
16 | 16 | public static class Source { | |
17 | - | private final ArrayList<String> content; | |
17 | + | private final List<String> content; | |
18 | 18 | private final boolean wasei; | |
19 | 19 | private final String language; | |
20 | 20 | ||
21 | - | public Source(ArrayList<String> content, boolean wasei, String language) { | |
21 | + | public Source(List<String> content, boolean wasei, String language) { | |
22 | 22 | this.content = content; | |
23 | 23 | this.wasei = wasei; | |
24 | 24 | this.language = language; | |
… | |||
26 | 26 | } | |
27 | 27 | ||
28 | 28 | public static class Sense { | |
29 | - | private final ArrayList<String> references, limits, infos, glosses; | |
29 | + | private final List<String> references, limits, infos, glosses; | |
30 | 30 | private final String language; | |
31 | - | private final ArrayList<Source> sources; | |
31 | + | private final List<Source> sources; | |
32 | 32 | ||
33 | - | public Sense(ArrayList<String> references, ArrayList<String> limits, ArrayList<String> infos, | |
34 | - | ArrayList<Source> sources, ArrayList<String> glosses, | |
33 | + | public Sense(List<String> references, List<String> limits, List<String> infos, | |
34 | + | List<Source> sources, List<String> glosses, | |
35 | 35 | String language) { | |
36 | 36 | this.references = references; | |
37 | 37 | this.limits = limits; | |
… | |||
41 | 41 | this.language = language; | |
42 | 42 | } | |
43 | 43 | ||
44 | - | public ArrayList<String> getGlosses() { | |
44 | + | public List<String> getGlosses() { | |
45 | 45 | return glosses; | |
46 | 46 | } | |
47 | 47 | ||
… | |||
55 | 55 | } | |
56 | 56 | ||
57 | 57 | public static class Reading { | |
58 | - | private final ArrayList<String> kanjis, infos, readings, pitches; | |
58 | + | private final List<String> kanjis, infos, readings, pitches; | |
59 | 59 | ||
60 | - | public Reading(ArrayList<String> kanjis, ArrayList<String> infos, ArrayList<String> readings) { | |
60 | + | public Reading(List<String> kanjis, List<String> infos, List<String> readings) { | |
61 | 61 | this.kanjis = kanjis; | |
62 | 62 | this.infos = infos; | |
63 | 63 | this.readings = readings; | |
… | |||
77 | 77 | } | |
78 | 78 | } | |
79 | 79 | ||
80 | - | private final ArrayList<String> kanjis; | |
81 | - | private final ArrayList<Reading> readings; | |
82 | - | private final ArrayList<Sense> senses; | |
80 | + | private final List<String> kanjis; | |
81 | + | private final List<Reading> readings; | |
82 | + | private final List<Sense> senses; | |
83 | 83 | private final int score; | |
84 | 84 | ||
85 | - | public Result(ArrayList<String> kanjis, ArrayList<Reading> readings, ArrayList<Sense> senses, int score) { | |
85 | + | public Result(List<String> kanjis, List<Reading> readings, List<Sense> senses, int score) { | |
86 | 86 | this.kanjis = kanjis; | |
87 | 87 | this.readings = readings; | |
88 | 88 | this.senses = senses; | |
… | |||
96 | 96 | return k; | |
97 | 97 | } | |
98 | 98 | ||
99 | - | public ArrayList<String> getAlternatives() { | |
99 | + | public List<String> getAlternatives() { | |
100 | 100 | return kanjis; | |
101 | 101 | } | |
102 | 102 | ||
103 | - | public ArrayList<Sense> getSenses() { | |
103 | + | public List<Sense> getSenses() { | |
104 | 104 | return senses; | |
105 | 105 | } | |
106 | 106 | ||
107 | - | public ArrayList<Reading> getReadings() { | |
107 | + | public List<Reading> getReadings() { | |
108 | 108 | return readings; | |
109 | 109 | } | |
110 | 110 | ||
111 | 111 | public String getReading() { | |
112 | 112 | String reading = ""; | |
113 | 113 | if(readings.size() > 0) { | |
114 | - | ArrayList<String> rs = readings.get(0).readings; | |
114 | + | List<String> rs = readings.get(0).readings; | |
115 | 115 | if(rs.size() > 0) | |
116 | 116 | reading = rs.get(0); | |
117 | 117 | } | |
… | |||
126 | 126 | ||
127 | 127 | public String getPitch() { | |
128 | 128 | if(readings.size() > 0) { | |
129 | - | ArrayList<String> pitches = readings.get(0).pitches; | |
129 | + | List<String> pitches = readings.get(0).pitches; | |
130 | 130 | if(pitches.size() > 0) | |
131 | 131 | return pitches.get(0); | |
132 | 132 | } |
app/src/main/java/eu/lepiller/nani/views/KanjiStrokeView.java
94 | 94 | int color; | |
95 | 95 | int i = 0; | |
96 | 96 | int m = strokes.size(); | |
97 | - | paint.setTextSize((float)size/24); | |
98 | - | paint.setStyle(Paint.Style.STROKE); | |
97 | + | paint.setTextSize((float)size/12); | |
99 | 98 | for(KanjiResult.Stroke s: strokes) { | |
100 | 99 | color = getColor(i, m, scheme, defaultColor); | |
101 | 100 | paint.setColor(color); | |
102 | 101 | ||
103 | 102 | // Draw number | |
104 | 103 | paint.setStrokeWidth(2); | |
105 | - | canvas.drawText(String.valueOf(i),s.getNumX() / 109 * size, s.getNumY() / 109 * size, paint); | |
104 | + | paint.setStyle(Paint.Style.FILL_AND_STROKE); | |
105 | + | canvas.drawText(String.valueOf(i+1),s.getNumX() / 109 * size, s.getNumY() / 109 * size, paint); | |
106 | 106 | ||
107 | 107 | // Draw stroke | |
108 | 108 | path.set(s.getPath()); | |
… | |||
111 | 111 | path.transform(matrix); | |
112 | 112 | ||
113 | 113 | paint.setStrokeWidth((float)size/32); | |
114 | + | paint.setStyle(Paint.Style.STROKE); | |
114 | 115 | canvas.drawPath(path, paint); | |
115 | 116 | ||
116 | 117 | i++; |
app/src/main/res/values/dimens.xml
1 | 1 | <resources> | |
2 | 2 | <dimen name="fab_margin">16dp</dimen> | |
3 | 3 | <dimen name="title_size">32sp</dimen> | |
4 | - | <dimen name="huge_kanji_size">64sp</dimen> | |
4 | + | <dimen name="huge_kanji_size">128sp</dimen> | |
5 | 5 | <dimen name="subtitle_size">24sp</dimen> | |
6 | 6 | <dimen name="normal_size">18sp</dimen> | |
7 | 7 | <dimen name="text_margin">16dp</dimen> |