001 /*
002 * Copyright 1996-2005 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 /*
027 * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
028 * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
029 *
030 * The original version of this source code and documentation is copyrighted
031 * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
032 * materials are provided under terms of a License Agreement between Taligent
033 * and Sun. This technology is protected by multiple US and International
034 * patents. This notice and attribution to Taligent may not be removed.
035 * Taligent is a registered trademark of Taligent, Inc.
036 *
037 */
038
039 package java.text;
040
041 import java.lang.Character;
042 import java.util.Vector;
043 import sun.text.CollatorUtilities;
044 import sun.text.normalizer.NormalizerBase;
045
046 /**
047 * The <code>CollationElementIterator</code> class is used as an iterator
048 * to walk through each character of an international string. Use the iterator
049 * to return the ordering priority of the positioned character. The ordering
050 * priority of a character, which we refer to as a key, defines how a character
051 * is collated in the given collation object.
052 *
053 * <p>
054 * For example, consider the following in Spanish:
055 * <blockquote>
056 * <pre>
057 * "ca" -> the first key is key('c') and second key is key('a').
058 * "cha" -> the first key is key('ch') and second key is key('a').
059 * </pre>
060 * </blockquote>
061 * And in German,
062 * <blockquote>
063 * <pre>
064 * "\u00e4b"-> the first key is key('a'), the second key is key('e'), and
065 * the third key is key('b').
066 * </pre>
067 * </blockquote>
068 * The key of a character is an integer composed of primary order(short),
069 * secondary order(byte), and tertiary order(byte). Java strictly defines
070 * the size and signedness of its primitive data types. Therefore, the static
071 * functions <code>primaryOrder</code>, <code>secondaryOrder</code>, and
072 * <code>tertiaryOrder</code> return <code>int</code>, <code>short</code>,
073 * and <code>short</code> respectively to ensure the correctness of the key
074 * value.
075 *
076 * <p>
077 * Example of the iterator usage,
078 * <blockquote>
079 * <pre>
080 *
081 * String testString = "This is a test";
082 * RuleBasedCollator ruleBasedCollator = (RuleBasedCollator)Collator.getInstance();
083 * CollationElementIterator collationElementIterator = ruleBasedCollator.getCollationElementIterator(testString);
084 * int primaryOrder = CollationElementIterator.primaryOrder(collationElementIterator.next());
085 * </pre>
086 * </blockquote>
087 *
088 * <p>
089 * <code>CollationElementIterator.next</code> returns the collation order
090 * of the next character. A collation order consists of primary order,
091 * secondary order and tertiary order. The data type of the collation
092 * order is <strong>int</strong>. The first 16 bits of a collation order
093 * is its primary order; the next 8 bits is the secondary order and the
094 * last 8 bits is the tertiary order.
095 *
096 * @see Collator
097 * @see RuleBasedCollator
098 * @version 1.24 07/27/98
099 * @author Helena Shih, Laura Werner, Richard Gillam
100 */
101 public final class CollationElementIterator {
102 /**
103 * Null order which indicates the end of string is reached by the
104 * cursor.
105 */
106 public final static int NULLORDER = 0xffffffff;
107
108 /**
109 * CollationElementIterator constructor. This takes the source string and
110 * the collation object. The cursor will walk thru the source string based
111 * on the predefined collation rules. If the source string is empty,
112 * NULLORDER will be returned on the calls to next().
113 * @param sourceText the source string.
114 * @param order the collation object.
115 */
116 CollationElementIterator(String sourceText, RuleBasedCollator owner) {
117 this .owner = owner;
118 ordering = owner.getTables();
119 if (sourceText.length() != 0) {
120 NormalizerBase.Mode mode = CollatorUtilities
121 .toNormalizerMode(owner.getDecomposition());
122 text = new NormalizerBase(sourceText, mode);
123 }
124 }
125
126 /**
127 * CollationElementIterator constructor. This takes the source string and
128 * the collation object. The cursor will walk thru the source string based
129 * on the predefined collation rules. If the source string is empty,
130 * NULLORDER will be returned on the calls to next().
131 * @param sourceText the source string.
132 * @param order the collation object.
133 */
134 CollationElementIterator(CharacterIterator sourceText,
135 RuleBasedCollator owner) {
136 this .owner = owner;
137 ordering = owner.getTables();
138 NormalizerBase.Mode mode = CollatorUtilities
139 .toNormalizerMode(owner.getDecomposition());
140 text = new NormalizerBase(sourceText, mode);
141 }
142
143 /**
144 * Resets the cursor to the beginning of the string. The next call
145 * to next() will return the first collation element in the string.
146 */
147 public void reset() {
148 if (text != null) {
149 text.reset();
150 NormalizerBase.Mode mode = CollatorUtilities
151 .toNormalizerMode(owner.getDecomposition());
152 text.setMode(mode);
153 }
154 buffer = null;
155 expIndex = 0;
156 swapOrder = 0;
157 }
158
159 /**
160 * Get the next collation element in the string. <p>This iterator iterates
161 * over a sequence of collation elements that were built from the string.
162 * Because there isn't necessarily a one-to-one mapping from characters to
163 * collation elements, this doesn't mean the same thing as "return the
164 * collation element [or ordering priority] of the next character in the
165 * string".</p>
166 * <p>This function returns the collation element that the iterator is currently
167 * pointing to and then updates the internal pointer to point to the next element.
168 * previous() updates the pointer first and then returns the element. This
169 * means that when you change direction while iterating (i.e., call next() and
170 * then call previous(), or call previous() and then call next()), you'll get
171 * back the same element twice.</p>
172 */
173 public int next() {
174 if (text == null) {
175 return NULLORDER;
176 }
177 NormalizerBase.Mode textMode = text.getMode();
178 // convert the owner's mode to something the Normalizer understands
179 NormalizerBase.Mode ownerMode = CollatorUtilities
180 .toNormalizerMode(owner.getDecomposition());
181 if (textMode != ownerMode) {
182 text.setMode(ownerMode);
183 }
184
185 // if buffer contains any decomposed char values
186 // return their strength orders before continuing in
187 // the Normalizer's CharacterIterator.
188 if (buffer != null) {
189 if (expIndex < buffer.length) {
190 return strengthOrder(buffer[expIndex++]);
191 } else {
192 buffer = null;
193 expIndex = 0;
194 }
195 } else if (swapOrder != 0) {
196 if (Character.isSupplementaryCodePoint(swapOrder)) {
197 char[] chars = Character.toChars(swapOrder);
198 swapOrder = chars[1];
199 return chars[0] << 16;
200 }
201 int order = swapOrder << 16;
202 swapOrder = 0;
203 return order;
204 }
205 int ch = text.next();
206
207 // are we at the end of Normalizer's text?
208 if (ch == NormalizerBase.DONE) {
209 return NULLORDER;
210 }
211
212 int value = ordering.getUnicodeOrder(ch);
213 if (value == RuleBasedCollator.UNMAPPED) {
214 swapOrder = ch;
215 return UNMAPPEDCHARVALUE;
216 } else if (value >= RuleBasedCollator.CONTRACTCHARINDEX) {
217 value = nextContractChar(ch);
218 }
219 if (value >= RuleBasedCollator.EXPANDCHARINDEX) {
220 buffer = ordering.getExpandValueList(value);
221 expIndex = 0;
222 value = buffer[expIndex++];
223 }
224
225 if (ordering.isSEAsianSwapping()) {
226 int consonant;
227 if (isThaiPreVowel(ch)) {
228 consonant = text.next();
229 if (isThaiBaseConsonant(consonant)) {
230 buffer = makeReorderedBuffer(consonant, value,
231 buffer, true);
232 value = buffer[0];
233 expIndex = 1;
234 } else {
235 text.previous();
236 }
237 }
238 if (isLaoPreVowel(ch)) {
239 consonant = text.next();
240 if (isLaoBaseConsonant(consonant)) {
241 buffer = makeReorderedBuffer(consonant, value,
242 buffer, true);
243 value = buffer[0];
244 expIndex = 1;
245 } else {
246 text.previous();
247 }
248 }
249 }
250
251 return strengthOrder(value);
252 }
253
254 /**
255 * Get the previous collation element in the string. <p>This iterator iterates
256 * over a sequence of collation elements that were built from the string.
257 * Because there isn't necessarily a one-to-one mapping from characters to
258 * collation elements, this doesn't mean the same thing as "return the
259 * collation element [or ordering priority] of the previous character in the
260 * string".</p>
261 * <p>This function updates the iterator's internal pointer to point to the
262 * collation element preceding the one it's currently pointing to and then
263 * returns that element, while next() returns the current element and then
264 * updates the pointer. This means that when you change direction while
265 * iterating (i.e., call next() and then call previous(), or call previous()
266 * and then call next()), you'll get back the same element twice.</p>
267 * @since 1.2
268 */
269 public int previous() {
270 if (text == null) {
271 return NULLORDER;
272 }
273 NormalizerBase.Mode textMode = text.getMode();
274 // convert the owner's mode to something the Normalizer understands
275 NormalizerBase.Mode ownerMode = CollatorUtilities
276 .toNormalizerMode(owner.getDecomposition());
277 if (textMode != ownerMode) {
278 text.setMode(ownerMode);
279 }
280 if (buffer != null) {
281 if (expIndex > 0) {
282 return strengthOrder(buffer[--expIndex]);
283 } else {
284 buffer = null;
285 expIndex = 0;
286 }
287 } else if (swapOrder != 0) {
288 if (Character.isSupplementaryCodePoint(swapOrder)) {
289 char[] chars = Character.toChars(swapOrder);
290 swapOrder = chars[1];
291 return chars[0] << 16;
292 }
293 int order = swapOrder << 16;
294 swapOrder = 0;
295 return order;
296 }
297 int ch = text.previous();
298 if (ch == NormalizerBase.DONE) {
299 return NULLORDER;
300 }
301
302 int value = ordering.getUnicodeOrder(ch);
303
304 if (value == RuleBasedCollator.UNMAPPED) {
305 swapOrder = UNMAPPEDCHARVALUE;
306 return ch;
307 } else if (value >= RuleBasedCollator.CONTRACTCHARINDEX) {
308 value = prevContractChar(ch);
309 }
310 if (value >= RuleBasedCollator.EXPANDCHARINDEX) {
311 buffer = ordering.getExpandValueList(value);
312 expIndex = buffer.length;
313 value = buffer[--expIndex];
314 }
315
316 if (ordering.isSEAsianSwapping()) {
317 int vowel;
318 if (isThaiBaseConsonant(ch)) {
319 vowel = text.previous();
320 if (isThaiPreVowel(vowel)) {
321 buffer = makeReorderedBuffer(vowel, value, buffer,
322 false);
323 expIndex = buffer.length - 1;
324 value = buffer[expIndex];
325 } else {
326 text.next();
327 }
328 }
329 if (isLaoBaseConsonant(ch)) {
330 vowel = text.previous();
331 if (isLaoPreVowel(vowel)) {
332 buffer = makeReorderedBuffer(vowel, value, buffer,
333 false);
334 expIndex = buffer.length - 1;
335 value = buffer[expIndex];
336 } else {
337 text.next();
338 }
339 }
340 }
341
342 return strengthOrder(value);
343 }
344
345 /**
346 * Return the primary component of a collation element.
347 * @param order the collation element
348 * @return the element's primary component
349 */
350 public final static int primaryOrder(int order) {
351 order &= RBCollationTables.PRIMARYORDERMASK;
352 return (order >>> RBCollationTables.PRIMARYORDERSHIFT);
353 }
354
355 /**
356 * Return the secondary component of a collation element.
357 * @param order the collation element
358 * @return the element's secondary component
359 */
360 public final static short secondaryOrder(int order) {
361 order = order & RBCollationTables.SECONDARYORDERMASK;
362 return ((short) (order >> RBCollationTables.SECONDARYORDERSHIFT));
363 }
364
365 /**
366 * Return the tertiary component of a collation element.
367 * @param order the collation element
368 * @return the element's tertiary component
369 */
370 public final static short tertiaryOrder(int order) {
371 return ((short) (order &= RBCollationTables.TERTIARYORDERMASK));
372 }
373
374 /**
375 * Get the comparison order in the desired strength. Ignore the other
376 * differences.
377 * @param order The order value
378 */
379 final int strengthOrder(int order) {
380 int s = owner.getStrength();
381 if (s == Collator.PRIMARY) {
382 order &= RBCollationTables.PRIMARYDIFFERENCEONLY;
383 } else if (s == Collator.SECONDARY) {
384 order &= RBCollationTables.SECONDARYDIFFERENCEONLY;
385 }
386 return order;
387 }
388
389 /**
390 * Sets the iterator to point to the collation element corresponding to
391 * the specified character (the parameter is a CHARACTER offset in the
392 * original string, not an offset into its corresponding sequence of
393 * collation elements). The value returned by the next call to next()
394 * will be the collation element corresponding to the specified position
395 * in the text. If that position is in the middle of a contracting
396 * character sequence, the result of the next call to next() is the
397 * collation element for that sequence. This means that getOffset()
398 * is not guaranteed to return the same value as was passed to a preceding
399 * call to setOffset().
400 *
401 * @param newOffset The new character offset into the original text.
402 * @since 1.2
403 */
404 public void setOffset(int newOffset) {
405 if (text != null) {
406 if (newOffset < text.getBeginIndex()
407 || newOffset >= text.getEndIndex()) {
408 text.setIndexOnly(newOffset);
409 } else {
410 int c = text.setIndex(newOffset);
411
412 // if the desired character isn't used in a contracting character
413 // sequence, bypass all the backing-up logic-- we're sitting on
414 // the right character already
415 if (ordering.usedInContractSeq(c)) {
416 // walk backwards through the string until we see a character
417 // that DOESN'T participate in a contracting character sequence
418 while (ordering.usedInContractSeq(c)) {
419 c = text.previous();
420 }
421 // now walk forward using this object's next() method until
422 // we pass the starting point and set our current position
423 // to the beginning of the last "character" before or at
424 // our starting position
425 int last = text.getIndex();
426 while (text.getIndex() <= newOffset) {
427 last = text.getIndex();
428 next();
429 }
430 text.setIndexOnly(last);
431 // we don't need this, since last is the last index
432 // that is the starting of the contraction which encompass
433 // newOffset
434 // text.previous();
435 }
436 }
437 }
438 buffer = null;
439 expIndex = 0;
440 swapOrder = 0;
441 }
442
443 /**
444 * Returns the character offset in the original text corresponding to the next
445 * collation element. (That is, getOffset() returns the position in the text
446 * corresponding to the collation element that will be returned by the next
447 * call to next().) This value will always be the index of the FIRST character
448 * corresponding to the collation element (a contracting character sequence is
449 * when two or more characters all correspond to the same collation element).
450 * This means if you do setOffset(x) followed immediately by getOffset(), getOffset()
451 * won't necessarily return x.
452 *
453 * @return The character offset in the original text corresponding to the collation
454 * element that will be returned by the next call to next().
455 * @since 1.2
456 */
457 public int getOffset() {
458 return (text != null) ? text.getIndex() : 0;
459 }
460
461 /**
462 * Return the maximum length of any expansion sequences that end
463 * with the specified comparison order.
464 * @param order a collation order returned by previous or next.
465 * @return the maximum length of any expansion sequences ending
466 * with the specified order.
467 * @since 1.2
468 */
469 public int getMaxExpansion(int order) {
470 return ordering.getMaxExpansion(order);
471 }
472
473 /**
474 * Set a new string over which to iterate.
475 *
476 * @param source the new source text
477 * @since 1.2
478 */
479 public void setText(String source) {
480 buffer = null;
481 swapOrder = 0;
482 expIndex = 0;
483 NormalizerBase.Mode mode = CollatorUtilities
484 .toNormalizerMode(owner.getDecomposition());
485 if (text == null) {
486 text = new NormalizerBase(source, mode);
487 } else {
488 text.setMode(mode);
489 text.setText(source);
490 }
491 }
492
493 /**
494 * Set a new string over which to iterate.
495 *
496 * @param source the new source text.
497 * @since 1.2
498 */
499 public void setText(CharacterIterator source) {
500 buffer = null;
501 swapOrder = 0;
502 expIndex = 0;
503 NormalizerBase.Mode mode = CollatorUtilities
504 .toNormalizerMode(owner.getDecomposition());
505 if (text == null) {
506 text = new NormalizerBase(source, mode);
507 } else {
508 text.setMode(mode);
509 text.setText(source);
510 }
511 }
512
513 //============================================================
514 // privates
515 //============================================================
516
517 /**
518 * Determine if a character is a Thai vowel (which sorts after
519 * its base consonant).
520 */
521 private final static boolean isThaiPreVowel(int ch) {
522 return (ch >= 0x0e40) && (ch <= 0x0e44);
523 }
524
525 /**
526 * Determine if a character is a Thai base consonant
527 */
528 private final static boolean isThaiBaseConsonant(int ch) {
529 return (ch >= 0x0e01) && (ch <= 0x0e2e);
530 }
531
532 /**
533 * Determine if a character is a Lao vowel (which sorts after
534 * its base consonant).
535 */
536 private final static boolean isLaoPreVowel(int ch) {
537 return (ch >= 0x0ec0) && (ch <= 0x0ec4);
538 }
539
540 /**
541 * Determine if a character is a Lao base consonant
542 */
543 private final static boolean isLaoBaseConsonant(int ch) {
544 return (ch >= 0x0e81) && (ch <= 0x0eae);
545 }
546
547 /**
548 * This method produces a buffer which contains the collation
549 * elements for the two characters, with colFirst's values preceding
550 * another character's. Presumably, the other character precedes colFirst
551 * in logical order (otherwise you wouldn't need this method would you?).
552 * The assumption is that the other char's value(s) have already been
553 * computed. If this char has a single element it is passed to this
554 * method as lastValue, and lastExpansion is null. If it has an
555 * expansion it is passed in lastExpansion, and colLastValue is ignored.
556 */
557 private int[] makeReorderedBuffer(int colFirst, int lastValue,
558 int[] lastExpansion, boolean forward) {
559
560 int[] result;
561
562 int firstValue = ordering.getUnicodeOrder(colFirst);
563 if (firstValue >= RuleBasedCollator.CONTRACTCHARINDEX) {
564 firstValue = forward ? nextContractChar(colFirst)
565 : prevContractChar(colFirst);
566 }
567
568 int[] firstExpansion = null;
569 if (firstValue >= RuleBasedCollator.EXPANDCHARINDEX) {
570 firstExpansion = ordering.getExpandValueList(firstValue);
571 }
572
573 if (!forward) {
574 int temp1 = firstValue;
575 firstValue = lastValue;
576 lastValue = temp1;
577 int[] temp2 = firstExpansion;
578 firstExpansion = lastExpansion;
579 lastExpansion = temp2;
580 }
581
582 if (firstExpansion == null && lastExpansion == null) {
583 result = new int[2];
584 result[0] = firstValue;
585 result[1] = lastValue;
586 } else {
587 int firstLength = firstExpansion == null ? 1
588 : firstExpansion.length;
589 int lastLength = lastExpansion == null ? 1
590 : lastExpansion.length;
591 result = new int[firstLength + lastLength];
592
593 if (firstExpansion == null) {
594 result[0] = firstValue;
595 } else {
596 System.arraycopy(firstExpansion, 0, result, 0,
597 firstLength);
598 }
599
600 if (lastExpansion == null) {
601 result[firstLength] = lastValue;
602 } else {
603 System.arraycopy(lastExpansion, 0, result, firstLength,
604 lastLength);
605 }
606 }
607
608 return result;
609 }
610
611 /**
612 * Check if a comparison order is ignorable.
613 * @return true if a character is ignorable, false otherwise.
614 */
615 final static boolean isIgnorable(int order) {
616 return ((primaryOrder(order) == 0) ? true : false);
617 }
618
619 /**
620 * Get the ordering priority of the next contracting character in the
621 * string.
622 * @param ch the starting character of a contracting character token
623 * @return the next contracting character's ordering. Returns NULLORDER
624 * if the end of string is reached.
625 */
626 private int nextContractChar(int ch) {
627 // First get the ordering of this single character,
628 // which is always the first element in the list
629 Vector list = ordering.getContractValues(ch);
630 EntryPair pair = (EntryPair) list.firstElement();
631 int order = pair.value;
632
633 // find out the length of the longest contracting character sequence in the list.
634 // There's logic in the builder code to make sure the longest sequence is always
635 // the last.
636 pair = (EntryPair) list.lastElement();
637 int maxLength = pair.entryName.length();
638
639 // (the Normalizer is cloned here so that the seeking we do in the next loop
640 // won't affect our real position in the text)
641 NormalizerBase tempText = (NormalizerBase) text.clone();
642
643 // extract the next maxLength characters in the string (we have to do this using the
644 // Normalizer to ensure that our offsets correspond to those the rest of the
645 // iterator is using) and store it in "fragment".
646 tempText.previous();
647 key.setLength(0);
648 int c = tempText.next();
649 while (maxLength > 0 && c != NormalizerBase.DONE) {
650 if (Character.isSupplementaryCodePoint(c)) {
651 key.append(Character.toChars(c));
652 maxLength -= 2;
653 } else {
654 key.append((char) c);
655 --maxLength;
656 }
657 c = tempText.next();
658 }
659 String fragment = key.toString();
660 // now that we have that fragment, iterate through this list looking for the
661 // longest sequence that matches the characters in the actual text. (maxLength
662 // is used here to keep track of the length of the longest sequence)
663 // Upon exit from this loop, maxLength will contain the length of the matching
664 // sequence and order will contain the collation-element value corresponding
665 // to this sequence
666 maxLength = 1;
667 for (int i = list.size() - 1; i > 0; i--) {
668 pair = (EntryPair) list.elementAt(i);
669 if (!pair.fwd)
670 continue;
671
672 if (fragment.startsWith(pair.entryName)
673 && pair.entryName.length() > maxLength) {
674 maxLength = pair.entryName.length();
675 order = pair.value;
676 }
677 }
678
679 // seek our current iteration position to the end of the matching sequence
680 // and return the appropriate collation-element value (if there was no matching
681 // sequence, we're already seeked to the right position and order already contains
682 // the correct collation-element value for the single character)
683 while (maxLength > 1) {
684 c = text.next();
685 maxLength -= Character.charCount(c);
686 }
687 return order;
688 }
689
690 /**
691 * Get the ordering priority of the previous contracting character in the
692 * string.
693 * @param ch the starting character of a contracting character token
694 * @return the next contracting character's ordering. Returns NULLORDER
695 * if the end of string is reached.
696 */
697 private int prevContractChar(int ch) {
698 // This function is identical to nextContractChar(), except that we've
699 // switched things so that the next() and previous() calls on the Normalizer
700 // are switched and so that we skip entry pairs with the fwd flag turned on
701 // rather than off. Notice that we still use append() and startsWith() when
702 // working on the fragment. This is because the entry pairs that are used
703 // in reverse iteration have their names reversed already.
704 Vector list = ordering.getContractValues(ch);
705 EntryPair pair = (EntryPair) list.firstElement();
706 int order = pair.value;
707
708 pair = (EntryPair) list.lastElement();
709 int maxLength = pair.entryName.length();
710
711 NormalizerBase tempText = (NormalizerBase) text.clone();
712
713 tempText.next();
714 key.setLength(0);
715 int c = tempText.previous();
716 while (maxLength > 0 && c != NormalizerBase.DONE) {
717 if (Character.isSupplementaryCodePoint(c)) {
718 key.append(Character.toChars(c));
719 maxLength -= 2;
720 } else {
721 key.append((char) c);
722 --maxLength;
723 }
724 c = tempText.previous();
725 }
726 String fragment = key.toString();
727
728 maxLength = 1;
729 for (int i = list.size() - 1; i > 0; i--) {
730 pair = (EntryPair) list.elementAt(i);
731 if (pair.fwd)
732 continue;
733
734 if (fragment.startsWith(pair.entryName)
735 && pair.entryName.length() > maxLength) {
736 maxLength = pair.entryName.length();
737 order = pair.value;
738 }
739 }
740
741 while (maxLength > 1) {
742 c = text.previous();
743 maxLength -= Character.charCount(c);
744 }
745 return order;
746 }
747
748 final static int UNMAPPEDCHARVALUE = 0x7FFF0000;
749
750 private NormalizerBase text = null;
751 private int[] buffer = null;
752 private int expIndex = 0;
753 private StringBuffer key = new StringBuffer(5);
754 private int swapOrder = 0;
755 private RBCollationTables ordering;
756 private RuleBasedCollator owner;
757 }
|