Showing the changes to java/pkg/sun/text/normalizer/Trie.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,419 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. | ||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| 4 | * | ||
| 5 | * This code is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License version 2 only, as | ||
| 7 | * published by the Free Software Foundation. Oracle designates this | ||
| 8 | * particular file as subject to the "Classpath" exception as provided | ||
| 9 | * by Oracle in the LICENSE file that accompanied this code. | ||
| 10 | * | ||
| 11 | * This code is distributed in the hope that it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 14 | * version 2 for more details (a copy is included in the LICENSE file that | ||
| 15 | * accompanied this code). | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License version | ||
| 18 | * 2 along with this work; if not, write to the Free Software Foundation, | ||
| 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 20 | * | ||
| 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
| 22 | * or visit www.oracle.com if you need additional information or have any | ||
| 23 | * questions. | ||
| 24 | */ | ||
| 25 | /* | ||
| 26 | ******************************************************************************* | ||
| 27 | * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved * | ||
| 28 | * * | ||
| 29 | * The original version of this source code and documentation is copyrighted * | ||
| 30 | * and owned by IBM, These materials are provided under terms of a License * | ||
| 31 | * Agreement between IBM and Sun. This technology is protected by multiple * | ||
| 32 | * US and International patents. This notice and attribution to IBM may not * | ||
| 33 | * to removed. * | ||
| 34 | ******************************************************************************* | ||
| 35 | */ | ||
| 36 | |||
| 37 | package sun.text.normalizer; | ||
| 38 | |||
| 39 | import java.io.DataInputStream; | ||
| 40 | import java.io.InputStream; | ||
| 41 | import java.io.IOException; | ||
| 42 | |||
| 43 | /** | ||
| 44 | * <p>A trie is a kind of compressed, serializable table of values | ||
| 45 | * associated with Unicode code points (0..0x10ffff).</p> | ||
| 46 | * <p>This class defines the basic structure of a trie and provides methods | ||
| 47 | * to <b>retrieve the offsets to the actual data</b>.</p> | ||
| 48 | * <p>Data will be the form of an array of basic types, char or int.</p> | ||
| 49 | * <p>The actual data format will have to be specified by the user in the | ||
| 50 | * inner static interface com.ibm.icu.impl.Trie.DataManipulate.</p> | ||
| 51 | * <p>This trie implementation is optimized for getting offset while walking | ||
| 52 | * forward through a UTF-16 string. | ||
| 53 | * Therefore, the simplest and fastest access macros are the | ||
| 54 | * fromLead() and fromOffsetTrail() methods. | ||
| 55 | * The fromBMP() method are a little more complicated; they get offsets even | ||
| 56 | * for lead surrogate codepoints, while the fromLead() method get special | ||
| 57 | * "folded" offsets for lead surrogate code units if there is relevant data | ||
| 58 | * associated with them. | ||
| 59 | * From such a folded offsets, an offset needs to be extracted to supply | ||
| 60 | * to the fromOffsetTrail() methods. | ||
| 61 | * To handle such supplementary codepoints, some offset information are kept | ||
| 62 | * in the data.</p> | ||
| 63 | * <p>Methods in com.ibm.icu.impl.Trie.DataManipulate are called to retrieve | ||
| 64 | * that offset from the folded value for the lead surrogate unit.</p> | ||
| 65 | * <p>For examples of use, see com.ibm.icu.impl.CharTrie or | ||
| 66 | * com.ibm.icu.impl.IntTrie.</p> | ||
| 67 | * @author synwee | ||
| 68 | * @see com.ibm.icu.impl.CharTrie | ||
| 69 | * @see com.ibm.icu.impl.IntTrie | ||
| 70 | * @since release 2.1, Jan 01 2002 | ||
| 71 | */ | ||
| 72 | public abstract class Trie | ||
| 73 | { | ||
| 74 | // public class declaration ---------------------------------------- | ||
| 75 | |||
| 76 | /** | ||
| 77 | * Character data in com.ibm.impl.Trie have different user-specified format | ||
| 78 | * for different purposes. | ||
| 79 | * This interface specifies methods to be implemented in order for | ||
| 80 | * com.ibm.impl.Trie, to surrogate offset information encapsulated within | ||
| 81 | * the data. | ||
| 82 | */ | ||
| 83 | public static interface DataManipulate | ||
| 84 | { | ||
| 85 | /** | ||
| 86 | * Called by com.ibm.icu.impl.Trie to extract from a lead surrogate's | ||
| 87 | * data | ||
| 88 | * the index array offset of the indexes for that lead surrogate. | ||
| 89 | * @param value data value for a surrogate from the trie, including the | ||
| 90 | * folding offset | ||
| 91 | * @return data offset or 0 if there is no data for the lead surrogate | ||
| 92 | */ | ||
| 93 | public int getFoldingOffset(int value); | ||
| 94 | } | ||
| 95 | |||
| 96 | // default implementation | ||
| 97 | private static class DefaultGetFoldingOffset implements DataManipulate { | ||
| 98 | public int getFoldingOffset(int value) { | ||
| 99 | return value; | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | // protected constructor ------------------------------------------- | ||
| 104 | |||
| 105 | /** | ||
| 106 | * Trie constructor for CharTrie use. | ||
| 107 | * @param inputStream ICU data file input stream which contains the | ||
| 108 | * trie | ||
| 109 | * @param dataManipulate object containing the information to parse the | ||
| 110 | * trie data | ||
| 111 | * @throws IOException thrown when input stream does not have the | ||
| 112 | * right header. | ||
| 113 | */ | ||
| 114 | protected Trie(InputStream inputStream, | ||
| 115 | DataManipulate dataManipulate) throws IOException | ||
| 116 | { | ||
| 117 | DataInputStream input = new DataInputStream(inputStream); | ||
| 118 | // Magic number to authenticate the data. | ||
| 119 | int signature = input.readInt(); | ||
| 120 | m_options_ = input.readInt(); | ||
| 121 | |||
| 122 | if (!checkHeader(signature)) { | ||
| 123 | throw new IllegalArgumentException("ICU data file error: Trie header authentication failed, please check if you have the most updated ICU data file"); | ||
| 124 | } | ||
| 125 | |||
| 126 | if(dataManipulate != null) { | ||
| 127 | m_dataManipulate_ = dataManipulate; | ||
| 128 | } else { | ||
| 129 | m_dataManipulate_ = new DefaultGetFoldingOffset(); | ||
| 130 | } | ||
| 131 | m_isLatin1Linear_ = (m_options_ & | ||
| 132 | HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_) != 0; | ||
| 133 | m_dataOffset_ = input.readInt(); | ||
| 134 | m_dataLength_ = input.readInt(); | ||
| 135 | unserialize(inputStream); | ||
| 136 | } | ||
| 137 | |||
| 138 | /** | ||
| 139 | * Trie constructor | ||
| 140 | * @param index array to be used for index | ||
| 141 | * @param options used by the trie | ||
| 142 | * @param dataManipulate object containing the information to parse the | ||
| 143 | * trie data | ||
| 144 | */ | ||
| 145 | protected Trie(char index[], int options, DataManipulate dataManipulate) | ||
| 146 | { | ||
| 147 | m_options_ = options; | ||
| 148 | if(dataManipulate != null) { | ||
| 149 | m_dataManipulate_ = dataManipulate; | ||
| 150 | } else { | ||
| 151 | m_dataManipulate_ = new DefaultGetFoldingOffset(); | ||
| 152 | } | ||
| 153 | m_isLatin1Linear_ = (m_options_ & | ||
| 154 | HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_) != 0; | ||
| 155 | m_index_ = index; | ||
| 156 | m_dataOffset_ = m_index_.length; | ||
| 157 | } | ||
| 158 | |||
| 159 | // protected data members ------------------------------------------ | ||
| 160 | |||
| 161 | /** | ||
| 162 | * Lead surrogate code points' index displacement in the index array. | ||
| 163 | * 0x10000-0xd800=0x2800 | ||
| 164 | * 0x2800 >> INDEX_STAGE_1_SHIFT_ | ||
| 165 | */ | ||
| 166 | protected static final int LEAD_INDEX_OFFSET_ = 0x2800 >> 5; | ||
| 167 | /** | ||
| 168 | * Shift size for shifting right the input index. 1..9 | ||
| 169 | */ | ||
| 170 | protected static final int INDEX_STAGE_1_SHIFT_ = 5; | ||
| 171 | /** | ||
| 172 | * Shift size for shifting left the index array values. | ||
| 173 | * Increases possible data size with 16-bit index values at the cost | ||
| 174 | * of compactability. | ||
| 175 | * This requires blocks of stage 2 data to be aligned by | ||
| 176 | * DATA_GRANULARITY. | ||
| 177 | * 0..INDEX_STAGE_1_SHIFT | ||
| 178 | */ | ||
| 179 | protected static final int INDEX_STAGE_2_SHIFT_ = 2; | ||
| 180 | /** | ||
| 181 | * Number of data values in a stage 2 (data array) block. | ||
| 182 | */ | ||
| 183 | protected static final int DATA_BLOCK_LENGTH=1<<INDEX_STAGE_1_SHIFT_; | ||
| 184 | /** | ||
| 185 | * Mask for getting the lower bits from the input index. | ||
| 186 | * DATA_BLOCK_LENGTH - 1. | ||
| 187 | */ | ||
| 188 | protected static final int INDEX_STAGE_3_MASK_ = DATA_BLOCK_LENGTH - 1; | ||
| 189 | /** Number of bits of a trail surrogate that are used in index table lookups. */ | ||
| 190 | protected static final int SURROGATE_BLOCK_BITS=10-INDEX_STAGE_1_SHIFT_; | ||
| 191 | /** | ||
| 192 | * Number of index (stage 1) entries per lead surrogate. | ||
| 193 | * Same as number of index entries for 1024 trail surrogates, | ||
| 194 | * ==0x400>>INDEX_STAGE_1_SHIFT_ | ||
| 195 | */ | ||
| 196 | protected static final int SURROGATE_BLOCK_COUNT=(1<<SURROGATE_BLOCK_BITS); | ||
| 197 | /** Length of the BMP portion of the index (stage 1) array. */ | ||
| 198 | protected static final int BMP_INDEX_LENGTH=0x10000>>INDEX_STAGE_1_SHIFT_; | ||
| 199 | /** | ||
| 200 | * Surrogate mask to use when shifting offset to retrieve supplementary | ||
| 201 | * values | ||
| 202 | */ | ||
| 203 | protected static final int SURROGATE_MASK_ = 0x3FF; | ||
| 204 | /** | ||
| 205 | * Index or UTF16 characters | ||
| 206 | */ | ||
| 207 | protected char m_index_[]; | ||
| 208 | /** | ||
| 209 | * Internal TrieValue which handles the parsing of the data value. | ||
| 210 | * This class is to be implemented by the user | ||
| 211 | */ | ||
| 212 | protected DataManipulate m_dataManipulate_; | ||
| 213 | /** | ||
| 214 | * Start index of the data portion of the trie. CharTrie combines | ||
| 215 | * index and data into a char array, so this is used to indicate the | ||
| 216 | * initial offset to the data portion. | ||
| 217 | * Note this index always points to the initial value. | ||
| 218 | */ | ||
| 219 | protected int m_dataOffset_; | ||
| 220 | /** | ||
| 221 | * Length of the data array | ||
| 222 | */ | ||
| 223 | protected int m_dataLength_; | ||
| 224 | |||
| 225 | // protected methods ----------------------------------------------- | ||
| 226 | |||
| 227 | /** | ||
| 228 | * Gets the offset to the data which the surrogate pair points to. | ||
| 229 | * @param lead lead surrogate | ||
| 230 | * @param trail trailing surrogate | ||
| 231 | * @return offset to data | ||
| 232 | */ | ||
| 233 | protected abstract int getSurrogateOffset(char lead, char trail); | ||
| 234 | |||
| 235 | /** | ||
| 236 | * Gets the value at the argument index | ||
| 237 | * @param index value at index will be retrieved | ||
| 238 | * @return 32 bit value | ||
| 239 | */ | ||
| 240 | protected abstract int getValue(int index); | ||
| 241 | |||
| 242 | /** | ||
| 243 | * Gets the default initial value | ||
| 244 | * @return 32 bit value | ||
| 245 | */ | ||
| 246 | protected abstract int getInitialValue(); | ||
| 247 | |||
| 248 | /** | ||
| 249 | * Gets the offset to the data which the index ch after variable offset | ||
| 250 | * points to. | ||
| 251 | * Note for locating a non-supplementary character data offset, calling | ||
| 252 | * <p> | ||
| 253 | * getRawOffset(0, ch); | ||
| 254 | * </p> | ||
| 255 | * will do. Otherwise if it is a supplementary character formed by | ||
| 256 | * surrogates lead and trail. Then we would have to call getRawOffset() | ||
| 257 | * with getFoldingIndexOffset(). See getSurrogateOffset(). | ||
| 258 | * @param offset index offset which ch is to start from | ||
| 259 | * @param ch index to be used after offset | ||
| 260 | * @return offset to the data | ||
| 261 | */ | ||
| 262 | protected final int getRawOffset(int offset, char ch) | ||
| 263 | { | ||
| 264 | return (m_index_[offset + (ch >> INDEX_STAGE_1_SHIFT_)] | ||
| 265 | << INDEX_STAGE_2_SHIFT_) | ||
| 266 | + (ch & INDEX_STAGE_3_MASK_); | ||
| 267 | } | ||
| 268 | |||
| 269 | /** | ||
| 270 | * Gets the offset to data which the BMP character points to | ||
| 271 | * Treats a lead surrogate as a normal code point. | ||
| 272 | * @param ch BMP character | ||
| 273 | * @return offset to data | ||
| 274 | */ | ||
| 275 | protected final int getBMPOffset(char ch) | ||
| 276 | { | ||
| 277 | return (ch >= UTF16.LEAD_SURROGATE_MIN_VALUE | ||
| 278 | && ch <= UTF16.LEAD_SURROGATE_MAX_VALUE) | ||
| 279 | ? getRawOffset(LEAD_INDEX_OFFSET_, ch) | ||
| 280 | : getRawOffset(0, ch); | ||
| 281 | // using a getRawOffset(ch) makes no diff | ||
| 282 | } | ||
| 283 | |||
| 284 | /** | ||
| 285 | * Gets the offset to the data which this lead surrogate character points | ||
| 286 | * to. | ||
| 287 | * Data at the returned offset may contain folding offset information for | ||
| 288 | * the next trailing surrogate character. | ||
| 289 | * @param ch lead surrogate character | ||
| 290 | * @return offset to data | ||
| 291 | */ | ||
| 292 | protected final int getLeadOffset(char ch) | ||
| 293 | { | ||
| 294 | return getRawOffset(0, ch); | ||
| 295 | } | ||
| 296 | |||
| 297 | /** | ||
| 298 | * Internal trie getter from a code point. | ||
| 299 | * Could be faster(?) but longer with | ||
| 300 | * if((c32)<=0xd7ff) { (result)=_TRIE_GET_RAW(trie, data, 0, c32); } | ||
| 301 | * Gets the offset to data which the codepoint points to | ||
| 302 | * @param ch codepoint | ||
| 303 | * @return offset to data | ||
| 304 | */ | ||
| 305 | protected final int getCodePointOffset(int ch) | ||
| 306 | { | ||
| 307 | // if ((ch >> 16) == 0) slower | ||
| 308 | if (ch < 0) { | ||
| 309 | return -1; | ||
| 310 | } else if (ch < UTF16.LEAD_SURROGATE_MIN_VALUE) { | ||
| 311 | // fastpath for the part of the BMP below surrogates (D800) where getRawOffset() works | ||
| 312 | return getRawOffset(0, (char)ch); | ||
| 313 | } else if (ch < UTF16.SUPPLEMENTARY_MIN_VALUE) { | ||
| 314 | // BMP codepoint | ||
| 315 | return getBMPOffset((char)ch); | ||
| 316 | } else if (ch <= UCharacter.MAX_VALUE) { | ||
| 317 | // look at the construction of supplementary characters | ||
| 318 | // trail forms the ends of it. | ||
| 319 | return getSurrogateOffset(UTF16.getLeadSurrogate(ch), | ||
| 320 | (char)(ch & SURROGATE_MASK_)); | ||
| 321 | } else { | ||
| 322 | // return -1 // if there is an error, in this case we return | ||
| 323 | return -1; | ||
| 324 | } | ||
| 325 | } | ||
| 326 | |||
| 327 | /** | ||
| 328 | * <p>Parses the inputstream and creates the trie index with it.</p> | ||
| 329 | * <p>This is overwritten by the child classes. | ||
| 330 | * @param inputStream input stream containing the trie information | ||
| 331 | * @exception IOException thrown when data reading fails. | ||
| 332 | */ | ||
| 333 | protected void unserialize(InputStream inputStream) throws IOException | ||
| 334 | { | ||
| 335 | //indexLength is a multiple of 1024 >> INDEX_STAGE_2_SHIFT_ | ||
| 336 | m_index_ = new char[m_dataOffset_]; | ||
| 337 | DataInputStream input = new DataInputStream(inputStream); | ||
| 338 | for (int i = 0; i < m_dataOffset_; i ++) { | ||
| 339 | m_index_[i] = input.readChar(); | ||
| 340 | } | ||
| 341 | } | ||
| 342 | |||
| 343 | /** | ||
| 344 | * Determines if this is a 32 bit trie | ||
| 345 | * @return true if options specifies this is a 32 bit trie | ||
| 346 | */ | ||
| 347 | protected final boolean isIntTrie() | ||
| 348 | { | ||
| 349 | return (m_options_ & HEADER_OPTIONS_DATA_IS_32_BIT_) != 0; | ||
| 350 | } | ||
| 351 | |||
| 352 | /** | ||
| 353 | * Determines if this is a 16 bit trie | ||
| 354 | * @return true if this is a 16 bit trie | ||
| 355 | */ | ||
| 356 | protected final boolean isCharTrie() | ||
| 357 | { | ||
| 358 | return (m_options_ & HEADER_OPTIONS_DATA_IS_32_BIT_) == 0; | ||
| 359 | } | ||
| 360 | |||
| 361 | // private data members -------------------------------------------- | ||
| 362 | |||
| 363 | /** | ||
| 364 | * Latin 1 option mask | ||
| 365 | */ | ||
| 366 | protected static final int HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_ = 0x200; | ||
| 367 | /** | ||
| 368 | * Constant number to authenticate the byte block | ||
| 369 | */ | ||
| 370 | protected static final int HEADER_SIGNATURE_ = 0x54726965; | ||
| 371 | /** | ||
| 372 | * Header option formatting | ||
| 373 | */ | ||
| 374 | private static final int HEADER_OPTIONS_SHIFT_MASK_ = 0xF; | ||
| 375 | protected static final int HEADER_OPTIONS_INDEX_SHIFT_ = 4; | ||
| 376 | protected static final int HEADER_OPTIONS_DATA_IS_32_BIT_ = 0x100; | ||
| 377 | |||
| 378 | /** | ||
| 379 | * Flag indicator for Latin quick access data block | ||
| 380 | */ | ||
| 381 | private boolean m_isLatin1Linear_; | ||
| 382 | |||
| 383 | /** | ||
| 384 | * <p>Trie options field.</p> | ||
| 385 | * <p>options bit field:<br> | ||
| 386 | * 9 1 = Latin-1 data is stored linearly at data + DATA_BLOCK_LENGTH<br> | ||
| 387 | * 8 0 = 16-bit data, 1=32-bit data<br> | ||
| 388 | * 7..4 INDEX_STAGE_1_SHIFT // 0..INDEX_STAGE_2_SHIFT<br> | ||
| 389 | * 3..0 INDEX_STAGE_2_SHIFT // 1..9<br> | ||
| 390 | */ | ||
| 391 | private int m_options_; | ||
| 392 | |||
| 393 | // private methods --------------------------------------------------- | ||
| 394 | |||
| 395 | /** | ||
| 396 | * Authenticates raw data header. | ||
| 397 | * Checking the header information, signature and options. | ||
| 398 | * @param signature This contains the options and type of a Trie | ||
| 399 | * @return true if the header is authenticated valid | ||
| 400 | */ | ||
| 401 | private final boolean checkHeader(int signature) | ||
| 402 | { | ||
| 403 | // check the signature | ||
| 404 | // Trie in big-endian US-ASCII (0x54726965). | ||
| 405 | // Magic number to authenticate the data. | ||
| 406 | if (signature != HEADER_SIGNATURE_) { | ||
| 407 | return false; | ||
| 408 | } | ||
| 409 | |||
| 410 | if ((m_options_ & HEADER_OPTIONS_SHIFT_MASK_) != | ||
| 411 | INDEX_STAGE_1_SHIFT_ || | ||
| 412 | ((m_options_ >> HEADER_OPTIONS_INDEX_SHIFT_) & | ||
| 413 | HEADER_OPTIONS_SHIFT_MASK_) | ||
| 414 | != INDEX_STAGE_2_SHIFT_) { | ||
| 415 | return false; | ||
| 416 | } | ||
| 417 | return true; | ||
| 418 | } | ||
| 419 | } | ||