181d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada/* 281d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * Copyright (C) 2012 The Android Open Source Project 381d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * 48aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); 58aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * you may not use this file except in compliance with the License. 68aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * You may obtain a copy of the License at 781d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * 88aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 981d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * 1081d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * Unless required by applicable law or agreed to in writing, software 118aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, 128aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * See the License for the specific language governing permissions and 148aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * limitations under the License. 1581d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada */ 1681d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada 1781d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanadapackage com.android.inputmethod.latin.makedict; 1881d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada 197d1ae52ded0deca6b2674df0273ec852ad36319fYuichiro Hanadaimport com.android.inputmethod.annotations.UsedForTesting; 2081d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanadaimport com.android.inputmethod.latin.Constants; 2181d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada 223ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagiimport java.util.Date; 233ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagiimport java.util.HashMap; 240e40cd0c40f2c731f91ccd0561e251262e5a2614Yuichiro Hanada 2581d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada/** 2681d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * Dictionary File Format Specification. 2781d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada */ 2881d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanadapublic final class FormatSpec { 2981d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada 3081d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada /* 317ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * File header layout is as follows: 327ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * 337ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * v | 347ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * e | MAGIC_NUMBER + version of the file format, 2 bytes. 357ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * r | 367ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * sion 377ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * 387ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * o | 399514ed5c2a49e645e2d468f7191d54d77d9f127fYuichiro Hanada * p | not used 3 bits 409514ed5c2a49e645e2d468f7191d54d77d9f127fYuichiro Hanada * t | each unigram and bigram entry has a time stamp? 419514ed5c2a49e645e2d468f7191d54d77d9f127fYuichiro Hanada * i | 1 bit, 1 = yes, 0 = no : CONTAINS_TIMESTAMP_FLAG 427b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * o | 437b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * nflags 447ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * 457ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * h | 467ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * e | size of the file header, 4bytes 477ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * a | including the size of the magic number, the option flags and the header size 487ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * d | 497ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * ersize 507ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * 517ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * | attributes list 527ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * 537ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * attributes list is: 547ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * <key> = | string of characters at the char format described below, with the terminator used 557ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * | to signal the end of the string. 567ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * <value> = | string of characters at the char format described below, with the terminator used 577ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * | to signal the end of the string. 587ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * if the size of already read < headersize, goto key. 597ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada * 607ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada */ 617ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada 627ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada /* 63af30cbf0ee8370763edf22822ea34a282e882084Jean Chalard * Node array (FusionDictionary.PtNodeArray) layout is as follows: 6481d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * 65576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * n | 66576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * o | the number of PtNodes, 1 or 2 bytes. 67576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * d | 1 byte = bbbbbbbb match 68576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * e | case 1xxxxxxx => xxxxxxx << 8 + next byte 69576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * c | otherwise => bbbbbbbb 70576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * o | 71576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * unt 7281d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * 73576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * n | 74576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * o | sequence of PtNodes, 75576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * d | the layout of each PtNode is described below. 76576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * e | 77576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * s 7881d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * 79061d225fb1d110695b396a470d9ae6a9a3331003Yuichiro Hanada * f | 807b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * o | forward link address, 3byte 817b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * r | 1 byte = bbbbbbbb match 827b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * w | case 1xxxxxxx => -((xxxxxxx << 16) + (next byte << 8) + next byte) 837b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * a | otherwise => (xxxxxxx << 16) + (next byte << 8) + next byte 847b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * r | 857b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * dlinkaddress 8681d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada */ 8781d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada 88576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada /* Node (FusionDictionary.PtNode) layout is as follows: 897b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * | is moved ? 2 bits, 11 = no : FLAG_IS_NOT_MOVED 907b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * | This must be the same as FLAG_CHILDREN_ADDRESS_TYPE_THREEBYTES 917b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * | 01 = yes : FLAG_IS_MOVED 927b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * f | the new address is stored in the same place as the parent address 937b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * l | is deleted? 10 = yes : FLAG_IS_DELETED 947b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * a | has several chars ? 1 bit, 1 = yes, 0 = no : FLAG_HAS_MULTIPLE_CHARS 957b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * g | has a terminal ? 1 bit, 1 = yes, 0 = no : FLAG_IS_TERMINAL 967b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * s | has shortcut targets ? 1 bit, 1 = yes, 0 = no : FLAG_HAS_SHORTCUT_TARGETS 9781d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * | has bigrams ? 1 bit, 1 = yes, 0 = no : FLAG_HAS_BIGRAMS 9881d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * | is not a word ? 1 bit, 1 = yes, 0 = no : FLAG_IS_NOT_A_WORD 9981d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * | is blacklisted ? 1 bit, 1 = yes, 0 = no : FLAG_IS_BLACKLISTED 10081d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * 10181d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * p | 1027b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * a | parent address, 3byte 1037b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * r | 1 byte = bbbbbbbb match 1047b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * e | case 1xxxxxxx => -((0xxxxxxx << 16) + (next byte << 8) + next byte) 1057b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * n | otherwise => (bbbbbbbb << 16) + (next byte << 8) + next byte 1067b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * t | This address is relative to the head of the PtNode. 1077b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * a | If the node doesn't have a parent, this field is set to 0. 108663f5375d1bad660a1fdfb43a3fb8dd1c3f64008Yuichiro Hanada * d | 1097b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * dress 11081d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * 11181d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * c | IF FLAG_HAS_MULTIPLE_CHARS 112576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * h | char, char, char, char n * (1 or 3 bytes) : use PtNodeInfo for i/o helpers 11381d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * a | end 1 byte, = 0 11481d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * r | ELSE 11581d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * s | char 1 or 3 bytes 11681d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * | END 11781d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * 11881d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * f | 11981d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * r | IF FLAG_IS_TERMINAL 12081d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * e | frequency 1 byte 12181d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * q | 12281d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * 1237b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * c | 1247b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * h | children address, 3 bytes 1257b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * i | 1 byte = bbbbbbbb match 1267b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * l | case 1xxxxxxx => -((0xxxxxxx << 16) + (next byte << 8) + next byte) 1277b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * d | otherwise => (bbbbbbbb<<16) + (next byte << 8) + next byte 1287b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * r | if this node doesn't have children, this field is set to 0. 1297b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * e | (see BinaryDictEncoderUtils#writeVariableSignedAddress) 1307b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * n | This address is relative to the position of this field. 1317b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * a | 1327b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard * ddress 13381d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * 13481d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * | IF FLAG_IS_TERMINAL && FLAG_HAS_SHORTCUT_TARGETS 13581d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * | shortcut string list 13681d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * | IF FLAG_IS_TERMINAL && FLAG_HAS_BIGRAMS 13781d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * | bigrams address list 13881d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * 13981d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * Char format is: 14081d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * 1 byte = bbbbbbbb match 14181d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * case 000xxxxx: xxxxx << 16 + next byte << 8 + next byte 14281d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * else: if 00011111 (= 0x1F) : this is the terminator. This is a relevant choice because 14381d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * unicode code points range from 0 to 0x10FFFF, so any 3-byte value starting with 14481d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * 00011111 would be outside unicode. 14581d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * else: iso-latin-1 code 14681d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * This allows for the whole unicode range to be encoded, including chars outside of 14781d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * the BMP. Also everything in the iso-latin-1 charset is only 1 byte, except control 14881d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * characters which should never happen anyway (and still work, but take 3 bytes). 14981d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * 15081d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * bigram address list is: 151576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * <flags> = | hasNext = 1 bit, 1 = yes, 0 = no : FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT 152576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * | addressSign = 1 bit, : FLAG_BIGRAM_ATTR_OFFSET_NEGATIVE 15381d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * | 1 = must take -address, 0 = must take +address 154576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * | xx : mask with MASK_BIGRAM_ATTR_ADDRESS_TYPE 155576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * | addressFormat = 2 bits, 00 = unused : FLAG_BIGRAM_ATTR_ADDRESS_TYPE_ONEBYTE 156576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * | 01 = 1 byte : FLAG_BIGRAM_ATTR_ADDRESS_TYPE_ONEBYTE 157576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * | 10 = 2 bytes : FLAG_BIGRAM_ATTR_ADDRESS_TYPE_TWOBYTES 158576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * | 11 = 3 bytes : FLAG_BIGRAM_ATTR_ADDRESS_TYPE_THREEBYTES 159576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * | 4 bits : frequency : mask with FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY 160576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * <address> | IF (01 == FLAG_BIGRAM_ATTR_ADDRESS_TYPE_ONEBYTE == addressFormat) 16181d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * | read 1 byte, add top 4 bits 162576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * | ELSIF (10 == FLAG_BIGRAM_ATTR_ADDRESS_TYPE_TWOBYTES == addressFormat) 16381d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * | read 2 bytes, add top 4 bits 164576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * | ELSE // 11 == FLAG_BIGRAM_ATTR_ADDRESS_TYPE_THREEBYTES == addressFormat 16581d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * | read 3 bytes, add top 4 bits 16681d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * | END 167576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * | if (FLAG_BIGRAM_ATTR_OFFSET_NEGATIVE) then address = -address 168576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * if (FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT) goto bigram_and_shortcut_address_list_is 16981d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * 17081d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * shortcut string list is: 171576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * <byte size> = PTNODE_SHORTCUT_LIST_SIZE_SIZE bytes, big-endian: size of the list, in bytes. 172576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * <flags> = | hasNext = 1 bit, 1 = yes, 0 = no : FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT 17381d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * | reserved = 3 bits, must be 0 174576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * | 4 bits : frequency : mask with FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY 17581d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * <shortcut> = | string of characters at the char format described above, with the terminator 17681d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada * | used to signal the end of the string. 177576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada * if (FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT goto flags 17881d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada */ 17981d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada 1807ec9db2c34ee6bec2cbff6cf05cee9bf3c2f7122Yuichiro Hanada public static final int MAGIC_NUMBER = 0x9BC13AFE; 18181d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada static final int NOT_A_VERSION_NUMBER = -1; 18282d9deaaf252cd20f8918adbc7a4b9b8f2647c38Yuichiro Hanada static final int FIRST_VERSION_WITH_DYNAMIC_UPDATE = 3; 183a141d8ef7dcf8f942eb7bd4ca006f63da1744319Yuichiro Hanada static final int FIRST_VERSION_WITH_TERMINAL_ID = 4; 1842fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 1852fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // These MUST have the same values as the relevant constants in format_utils.h. 1862fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // From version 4 on, we use version * 100 + revision as a version number. That allows 1872fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // us to change the format during development while having testing devices remove 1882fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // older files with each upgrade, while still having a readable versioning scheme. 189455dc84cf2c6526329b535f30000ea45b7d4d4d7Keisuke Kuroyanagi // When we bump up the dictionary format version, we should update 190455dc84cf2c6526329b535f30000ea45b7d4d4d7Keisuke Kuroyanagi // ExpandableDictionary.needsToMigrateDictionary() and 191455dc84cf2c6526329b535f30000ea45b7d4d4d7Keisuke Kuroyanagi // ExpandableDictionary.matchesExpectedBinaryDictFormatVersionForThisType(). 1922fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public static final int VERSION2 = 2; 193455dc84cf2c6526329b535f30000ea45b7d4d4d7Keisuke Kuroyanagi // Dictionary version used for testing. 194455dc84cf2c6526329b535f30000ea45b7d4d4d7Keisuke Kuroyanagi public static final int VERSION4_ONLY_FOR_TESTING = 399; 195a37f374ad140f14e5e8ecaef9e1dbee3b1d7b84cKeisuke Kuroyanagi public static final int VERSION401 = 401; 196a37f374ad140f14e5e8ecaef9e1dbee3b1d7b84cKeisuke Kuroyanagi public static final int VERSION4 = 402; 197a37f374ad140f14e5e8ecaef9e1dbee3b1d7b84cKeisuke Kuroyanagi public static final int VERSION4_DEV = 403; 1982fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa static final int MINIMUM_SUPPORTED_VERSION = VERSION2; 19904536f14b02566ead3a95fc7d80d47e8d99936edKeisuke Kuroyanagi static final int MAXIMUM_SUPPORTED_VERSION = VERSION4_DEV; 20081d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada 20181d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada // TODO: Make this value adaptative to content data, store it in the header, and 20281d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada // use it in the reading code. 203ffcbbaf12788a9fc9398607a548e552d7d2bf05eSatoshi Kataoka static final int MAX_WORD_LENGTH = Constants.DICTIONARY_MAX_WORD_LENGTH; 20481d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada 20581d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada static final int PARENT_ADDRESS_SIZE = 3; 206061d225fb1d110695b396a470d9ae6a9a3331003Yuichiro Hanada static final int FORWARD_LINK_ADDRESS_SIZE = 3; 20781d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada 2084ad4ff618f5102148d73e3c04d809942bcf16f86Yuichiro Hanada // These flags are used only in the static dictionary. 209576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int MASK_CHILDREN_ADDRESS_TYPE = 0xC0; 210576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int FLAG_CHILDREN_ADDRESS_TYPE_NOADDRESS = 0x00; 211576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int FLAG_CHILDREN_ADDRESS_TYPE_ONEBYTE = 0x40; 212576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int FLAG_CHILDREN_ADDRESS_TYPE_TWOBYTES = 0x80; 213576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int FLAG_CHILDREN_ADDRESS_TYPE_THREEBYTES = 0xC0; 21481d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada 21581d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada static final int FLAG_HAS_MULTIPLE_CHARS = 0x20; 21681d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada 21781d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada static final int FLAG_IS_TERMINAL = 0x10; 21881d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada static final int FLAG_HAS_SHORTCUT_TARGETS = 0x08; 21981d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada static final int FLAG_HAS_BIGRAMS = 0x04; 22081d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada static final int FLAG_IS_NOT_A_WORD = 0x02; 22181d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada static final int FLAG_IS_BLACKLISTED = 0x01; 2224ad4ff618f5102148d73e3c04d809942bcf16f86Yuichiro Hanada 2234ad4ff618f5102148d73e3c04d809942bcf16f86Yuichiro Hanada // These flags are used only in the dynamic dictionary. 224c3a98ca306d5d6a3dfce3585b73f7431dbf90bfcYuichiro Hanada static final int MASK_MOVE_AND_DELETE_FLAG = 0xC0; 2254ad4ff618f5102148d73e3c04d809942bcf16f86Yuichiro Hanada static final int FIXED_BIT_OF_DYNAMIC_UPDATE_MOVE = 0x40; 2264ad4ff618f5102148d73e3c04d809942bcf16f86Yuichiro Hanada static final int FLAG_IS_MOVED = 0x00 | FIXED_BIT_OF_DYNAMIC_UPDATE_MOVE; 2274ad4ff618f5102148d73e3c04d809942bcf16f86Yuichiro Hanada static final int FLAG_IS_NOT_MOVED = 0x80 | FIXED_BIT_OF_DYNAMIC_UPDATE_MOVE; 228a853356b82e2dc74962243e3143c0ff7a33f3c20Yuichiro Hanada static final int FLAG_IS_DELETED = 0x80; 22981d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada 230576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int FLAG_BIGRAM_SHORTCUT_ATTR_HAS_NEXT = 0x80; 231576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int FLAG_BIGRAM_ATTR_OFFSET_NEGATIVE = 0x40; 232576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int MASK_BIGRAM_ATTR_ADDRESS_TYPE = 0x30; 233576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int FLAG_BIGRAM_ATTR_ADDRESS_TYPE_ONEBYTE = 0x10; 234576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int FLAG_BIGRAM_ATTR_ADDRESS_TYPE_TWOBYTES = 0x20; 235576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int FLAG_BIGRAM_ATTR_ADDRESS_TYPE_THREEBYTES = 0x30; 236576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY = 0x0F; 23781d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada 238576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int PTNODE_CHARACTERS_TERMINATOR = 0x1F; 23981d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada 240576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int PTNODE_TERMINATOR_SIZE = 1; 241576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int PTNODE_FLAGS_SIZE = 1; 242576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int PTNODE_FREQUENCY_SIZE = 1; 243a141d8ef7dcf8f942eb7bd4ca006f63da1744319Yuichiro Hanada static final int PTNODE_TERMINAL_ID_SIZE = 4; 244576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int PTNODE_MAX_ADDRESS_SIZE = 3; 245576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int PTNODE_ATTRIBUTE_FLAGS_SIZE = 1; 246576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int PTNODE_ATTRIBUTE_MAX_ADDRESS_SIZE = 3; 247576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int PTNODE_SHORTCUT_LIST_SIZE_SIZE = 2; 24881d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada 2492fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // These values are used only by version 4 or later. They MUST match the definitions in 2502fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // ver4_dict_constants.cpp. 251a141d8ef7dcf8f942eb7bd4ca006f63da1744319Yuichiro Hanada static final String TRIE_FILE_EXTENSION = ".trie"; 2522fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa public static final String HEADER_FILE_EXTENSION = ".header"; 253a141d8ef7dcf8f942eb7bd4ca006f63da1744319Yuichiro Hanada static final String FREQ_FILE_EXTENSION = ".freq"; 25422c5c450fecb856100059f4e5b34b847fb0acfa7Yuichiro Hanada // tat = Terminal Address Table 25522c5c450fecb856100059f4e5b34b847fb0acfa7Yuichiro Hanada static final String TERMINAL_ADDRESS_TABLE_FILE_EXTENSION = ".tat"; 256fd46e87da2e91583e0b0ab0dd7ffa5e329012861Yuichiro Hanada static final String BIGRAM_FILE_EXTENSION = ".bigram"; 25773b9d3b879c109a7b8487b609b0715ffe3090142Yuichiro Hanada static final String SHORTCUT_FILE_EXTENSION = ".shortcut"; 2583dd77a6d6696bb426b200b27adeb8be7e887a667Yuichiro Hanada static final String LOOKUP_TABLE_FILE_SUFFIX = "_lookup"; 2593dd77a6d6696bb426b200b27adeb8be7e887a667Yuichiro Hanada static final String CONTENT_TABLE_FILE_SUFFIX = "_index"; 26026bd46095a05843e7574dfcf7db53406f215525dKeisuke Kuroyanagi static final int FLAGS_IN_FREQ_FILE_SIZE = 1; 261a141d8ef7dcf8f942eb7bd4ca006f63da1744319Yuichiro Hanada static final int FREQUENCY_AND_FLAGS_SIZE = 2; 26222c5c450fecb856100059f4e5b34b847fb0acfa7Yuichiro Hanada static final int TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE = 3; 263c32962b8f1f9b7255fef84486b53cfc874835bbdYuichiro Hanada static final int UNIGRAM_TIMESTAMP_SIZE = 4; 26426bd46095a05843e7574dfcf7db53406f215525dKeisuke Kuroyanagi static final int UNIGRAM_COUNTER_SIZE = 1; 26526bd46095a05843e7574dfcf7db53406f215525dKeisuke Kuroyanagi static final int UNIGRAM_LEVEL_SIZE = 1; 26673b9d3b879c109a7b8487b609b0715ffe3090142Yuichiro Hanada 26773b9d3b879c109a7b8487b609b0715ffe3090142Yuichiro Hanada // With the English main dictionary as of October 2013, the size of bigram address table is 2682fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // is 345KB with the block size being 16. 2692fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // This is 54% of that of full address table. 2702fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa static final int BIGRAM_ADDRESS_TABLE_BLOCK_SIZE = 16; 27126bd46095a05843e7574dfcf7db53406f215525dKeisuke Kuroyanagi static final int BIGRAM_CONTENT_COUNT = 1; 2723dd77a6d6696bb426b200b27adeb8be7e887a667Yuichiro Hanada static final int BIGRAM_FREQ_CONTENT_INDEX = 0; 2733dd77a6d6696bb426b200b27adeb8be7e887a667Yuichiro Hanada static final String BIGRAM_FREQ_CONTENT_ID = "_freq"; 2749514ed5c2a49e645e2d468f7191d54d77d9f127fYuichiro Hanada static final int BIGRAM_TIMESTAMP_SIZE = 4; 2759514ed5c2a49e645e2d468f7191d54d77d9f127fYuichiro Hanada static final int BIGRAM_COUNTER_SIZE = 1; 2769514ed5c2a49e645e2d468f7191d54d77d9f127fYuichiro Hanada static final int BIGRAM_LEVEL_SIZE = 1; 277a141d8ef7dcf8f942eb7bd4ca006f63da1744319Yuichiro Hanada 27873b9d3b879c109a7b8487b609b0715ffe3090142Yuichiro Hanada static final int SHORTCUT_CONTENT_COUNT = 1; 27973b9d3b879c109a7b8487b609b0715ffe3090142Yuichiro Hanada static final int SHORTCUT_CONTENT_INDEX = 0; 28073b9d3b879c109a7b8487b609b0715ffe3090142Yuichiro Hanada // With the English main dictionary as of October 2013, the size of shortcut address table is 2812fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // 26KB with the block size being 64. 28273b9d3b879c109a7b8487b609b0715ffe3090142Yuichiro Hanada // This is only 4.4% of that of full address table. 28373b9d3b879c109a7b8487b609b0715ffe3090142Yuichiro Hanada static final int SHORTCUT_ADDRESS_TABLE_BLOCK_SIZE = 64; 28473b9d3b879c109a7b8487b609b0715ffe3090142Yuichiro Hanada static final String SHORTCUT_CONTENT_ID = "_shortcut"; 28573b9d3b879c109a7b8487b609b0715ffe3090142Yuichiro Hanada 28681d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada static final int NO_CHILDREN_ADDRESS = Integer.MIN_VALUE; 28781d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada static final int NO_PARENT_ADDRESS = 0; 288061d225fb1d110695b396a470d9ae6a9a3331003Yuichiro Hanada static final int NO_FORWARD_LINK_ADDRESS = 0; 28981d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada static final int INVALID_CHARACTER = -1; 29081d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada 291576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int MAX_PTNODES_FOR_ONE_BYTE_PTNODE_COUNT = 0x7F; // 127 292db4f3730047c8a3e25e031aacc07bb02bc47c5aeKeisuke Kuroyanagi // Large PtNode array size field size is 2 bytes. 293db4f3730047c8a3e25e031aacc07bb02bc47c5aeKeisuke Kuroyanagi static final int LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE_FLAG = 0x8000; 294576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int MAX_PTNODES_IN_A_PT_NODE_ARRAY = 0x7FFF; // 32767 295576f625ee1b22e26baab46cc4ad3138e901383e2Yuichiro Hanada static final int MAX_BIGRAMS_IN_A_PTNODE = 10000; 296a141d8ef7dcf8f942eb7bd4ca006f63da1744319Yuichiro Hanada static final int MAX_SHORTCUT_LIST_SIZE_IN_A_PTNODE = 0xFFFF; 29781d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada 29881d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada static final int MAX_TERMINAL_FREQUENCY = 255; 29981d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada static final int MAX_BIGRAM_FREQUENCY = 15; 30081d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada 30147cac57e4593f47e753410e4199e84e458d6de6fJean Chalard public static final int SHORTCUT_WHITELIST_FREQUENCY = 15; 30247cac57e4593f47e753410e4199e84e458d6de6fJean Chalard 303d36245fad292ea660ca49f38a3ec36e07727dda5Yuichiro Hanada // This option needs to be the same numeric value as the one in binary_format.h. 304d36245fad292ea660ca49f38a3ec36e07727dda5Yuichiro Hanada static final int NOT_VALID_WORD = -99; 3058ec0064c49e80945dbe1bb31129eb890478b7e06Yuichiro Hanada static final int SIGNED_CHILDREN_ADDRESS_SIZE = 3; 306d36245fad292ea660ca49f38a3ec36e07727dda5Yuichiro Hanada 307665592774c1d5ec90abbe772d4303fe8d8fe8089Yuichiro Hanada static final int UINT8_MAX = 0xFF; 308665592774c1d5ec90abbe772d4303fe8d8fe8089Yuichiro Hanada static final int UINT16_MAX = 0xFFFF; 309665592774c1d5ec90abbe772d4303fe8d8fe8089Yuichiro Hanada static final int UINT24_MAX = 0xFFFFFF; 310665592774c1d5ec90abbe772d4303fe8d8fe8089Yuichiro Hanada static final int SINT24_MAX = 0x7FFFFF; 311665592774c1d5ec90abbe772d4303fe8d8fe8089Yuichiro Hanada static final int MSB8 = 0x80; 312665592774c1d5ec90abbe772d4303fe8d8fe8089Yuichiro Hanada static final int MSB24 = 0x800000; 313665592774c1d5ec90abbe772d4303fe8d8fe8089Yuichiro Hanada 3141a347723c5ad4a71076df67f3af3b702db205719Yuichiro Hanada /** 3151a347723c5ad4a71076df67f3af3b702db205719Yuichiro Hanada * Options about file format. 3161a347723c5ad4a71076df67f3af3b702db205719Yuichiro Hanada */ 317a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaoka public static final class FormatOptions { 3181a347723c5ad4a71076df67f3af3b702db205719Yuichiro Hanada public final int mVersion; 3199514ed5c2a49e645e2d468f7191d54d77d9f127fYuichiro Hanada public final boolean mHasTimestamp; 3207d1ae52ded0deca6b2674df0273ec852ad36319fYuichiro Hanada 3217d1ae52ded0deca6b2674df0273ec852ad36319fYuichiro Hanada @UsedForTesting 3227b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard public FormatOptions(final int version) { 3237b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard this(version, false /* hasTimestamp */); 3249514ed5c2a49e645e2d468f7191d54d77d9f127fYuichiro Hanada } 3259514ed5c2a49e645e2d468f7191d54d77d9f127fYuichiro Hanada 3267b55cd3e2b4966150fa4c44dd43ebfeb77058a43Jean Chalard public FormatOptions(final int version, final boolean hasTimestamp) { 3271a347723c5ad4a71076df67f3af3b702db205719Yuichiro Hanada mVersion = version; 3289514ed5c2a49e645e2d468f7191d54d77d9f127fYuichiro Hanada mHasTimestamp = hasTimestamp; 3291a347723c5ad4a71076df67f3af3b702db205719Yuichiro Hanada } 3301a347723c5ad4a71076df67f3af3b702db205719Yuichiro Hanada } 3311a347723c5ad4a71076df67f3af3b702db205719Yuichiro Hanada 3321a347723c5ad4a71076df67f3af3b702db205719Yuichiro Hanada /** 3333ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi * Options global to the dictionary. 3343ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi */ 3353ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi public static final class DictionaryOptions { 3363ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi public final HashMap<String, String> mAttributes; 3373ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi public DictionaryOptions(final HashMap<String, String> attributes) { 3383ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi mAttributes = attributes; 3393ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi } 3403ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi @Override 3413ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi public String toString() { // Convenience method 3423ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi return toString(0, false); 3433ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi } 3443ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi public String toString(final int indentCount, final boolean plumbing) { 3453ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi final StringBuilder indent = new StringBuilder(); 3463ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi if (plumbing) { 3473ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi indent.append("H:"); 3483ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi } else { 3493ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi for (int i = 0; i < indentCount; ++i) { 3503ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi indent.append(" "); 3513ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi } 3523ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi } 3533ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi final StringBuilder s = new StringBuilder(); 3543ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi for (final String optionKey : mAttributes.keySet()) { 3553ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi s.append(indent); 3563ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi s.append(optionKey); 3573ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi s.append(" = "); 3583ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi if ("date".equals(optionKey) && !plumbing) { 3593ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi // Date needs a number of milliseconds, but the dictionary contains seconds 3603ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi s.append(new Date( 3613ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi 1000 * Long.parseLong(mAttributes.get(optionKey))).toString()); 3623ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi } else { 3633ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi s.append(mAttributes.get(optionKey)); 3643ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi } 3653ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi s.append("\n"); 3663ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi } 3673ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi return s.toString(); 3683ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi } 3693ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi } 3703ad4af2354e7003ac288dafe3600268fe860d752Keisuke Kuroyanagi 37181d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada private FormatSpec() { 37281d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada // This utility class is not publicly instantiable. 37381d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada } 37481d97eec0e77e72cce606f9c9f96091c0b348190Yuichiro Hanada} 375