1 /*
2 * Copyright 1996-2005 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 /*
27 * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28 * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
29 *
30 * The original version of this source code and documentation is copyrighted
31 * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32 * materials are provided under terms of a License Agreement between Taligent
33 * and Sun. This technology is protected by multiple US and International
34 * patents. This notice and attribution to Taligent may not be removed.
35 * Taligent is a registered trademark of Taligent, Inc.
36 *
37 */
38
39 package java.text;
40
41 import java.lang.Character;
42 import java.util.Vector;
43 import sun.text.CollatorUtilities;
44 import sun.text.normalizer.NormalizerBase;
45
46 /**
47 * The <code>CollationElementIterator</code> class is used as an iterator
48 * to walk through each character of an international string. Use the iterator
49 * to return the ordering priority of the positioned character. The ordering
50 * priority of a character, which we refer to as a key, defines how a character
51 * is collated in the given collation object.
52 *
53 * <p>
54 * For example, consider the following in Spanish:
55 * <blockquote>
56 * <pre>
57 * "ca" -> the first key is key('c') and second key is key('a').
58 * "cha" -> the first key is key('ch') and second key is key('a').
59 * </pre>
60 * </blockquote>
61 * And in German,
62 * <blockquote>
63 * <pre>
64 * "\u00e4b"-> the first key is key('a'), the second key is key('e'), and
65 * the third key is key('b').
66 * </pre>
67 * </blockquote>
68 * The key of a character is an integer composed of primary order(short),
69 * secondary order(byte), and tertiary order(byte). Java strictly defines
70 * the size and signedness of its primitive data types. Therefore, the static
71 * functions <code>primaryOrder</code>, <code>secondaryOrder</code>, and
72 * <code>tertiaryOrder</code> return <code>int</code>, <code>short</code>,
73 * and <code>short</code> respectively to ensure the correctness of the key
74 * value.
75 *
76 * <p>
77 * Example of the iterator usage,
78 * <blockquote>
79 * <pre>
80 *
81 * String testString = "This is a test";
82 * RuleBasedCollator ruleBasedCollator = (RuleBasedCollator)Collator.getInstance();
83 * CollationElementIterator collationElementIterator = ruleBasedCollator.getCollationElementIterator(testString);
84 * int primaryOrder = CollationElementIterator.primaryOrder(collationElementIterator.next());
85 * </pre>
86 * </blockquote>
87 *
88 * <p>
89 * <code>CollationElementIterator.next</code> returns the collation order
90 * of the next character. A collation order consists of primary order,
91 * secondary order and tertiary order. The data type of the collation
92 * order is <strong>int</strong>. The first 16 bits of a collation order
93 * is its primary order; the next 8 bits is the secondary order and the
94 * last 8 bits is the tertiary order.
95 *
96 * @see Collator
97 * @see RuleBasedCollator
98 * @author Helena Shih, Laura Werner, Richard Gillam
99 */
100 public final class CollationElementIterator
101 {
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 =
121 CollatorUtilities.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, RuleBasedCollator owner) {
135 this.owner = owner;
136 ordering = owner.getTables();
137 NormalizerBase.Mode mode =
138 CollatorUtilities.toNormalizerMode(owner.getDecomposition());
139 text = new NormalizerBase(sourceText, mode);
140 }
141
142 /**
143 * Resets the cursor to the beginning of the string. The next call
144 * to next() will return the first collation element in the string.
145 */
146 public void reset()
147 {
148 if (text != null) {
149 text.reset();
150 NormalizerBase.Mode mode =
151 CollatorUtilities.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 {
175 if (text == null) {
176 return NULLORDER;
177 }
178 NormalizerBase.Mode textMode = text.getMode();
179 // convert the owner's mode to something the Normalizer understands
180 NormalizerBase.Mode ownerMode =
181 CollatorUtilities.toNormalizerMode(owner.getDecomposition());
182 if (textMode != ownerMode) {
183 text.setMode(ownerMode);
184 }
185
186 // if buffer contains any decomposed char values
187 // return their strength orders before continuing in
188 // the Normalizer's CharacterIterator.
189 if (buffer != null) {
190 if (expIndex < buffer.length) {
191 return strengthOrder(buffer[expIndex++]);
192 } else {
193 buffer = null;
194 expIndex = 0;
195 }
196 } else if (swapOrder != 0) {
197 if (Character.isSupplementaryCodePoint(swapOrder)) {
198 char[] chars = Character.toChars(swapOrder);
199 swapOrder = chars[1];
200 return chars[0] << 16;
201 }
202 int order = swapOrder << 16;
203 swapOrder = 0;
204 return order;
205 }
206 int ch = text.next();
207
208 // are we at the end of Normalizer's text?
209 if (ch == NormalizerBase.DONE) {
210 return NULLORDER;
211 }
212
213 int value = ordering.getUnicodeOrder(ch);
214 if (value == RuleBasedCollator.UNMAPPED) {
215 swapOrder = ch;
216 return UNMAPPEDCHARVALUE;
217 }
218 else if (value >= RuleBasedCollator.CONTRACTCHARINDEX) {
219 value = nextContractChar(ch);
220 }
221 if (value >= RuleBasedCollator.EXPANDCHARINDEX) {
222 buffer = ordering.getExpandValueList(value);
223 expIndex = 0;
224 value = buffer[expIndex++];
225 }
226
227 if (ordering.isSEAsianSwapping()) {
228 int consonant;
229 if (isThaiPreVowel(ch)) {
230 consonant = text.next();
231 if (isThaiBaseConsonant(consonant)) {
232 buffer = makeReorderedBuffer(consonant, value, buffer, true);
233 value = buffer[0];
234 expIndex = 1;
235 } else {
236 text.previous();
237 }
238 }
239 if (isLaoPreVowel(ch)) {
240 consonant = text.next();
241 if (isLaoBaseConsonant(consonant)) {
242 buffer = makeReorderedBuffer(consonant, value, 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 {
271 if (text == null) {
272 return NULLORDER;
273 }
274 NormalizerBase.Mode textMode = text.getMode();
275 // convert the owner's mode to something the Normalizer understands
276 NormalizerBase.Mode ownerMode =
277 CollatorUtilities.toNormalizerMode(owner.getDecomposition());
278 if (textMode != ownerMode) {
279 text.setMode(ownerMode);
280 }
281 if (buffer != null) {
282 if (expIndex > 0) {
283 return strengthOrder(buffer[--expIndex]);
284 } else {
285 buffer = null;
286 expIndex = 0;
287 }
288 } else if (swapOrder != 0) {
289 if (Character.isSupplementaryCodePoint(swapOrder)) {
290 char[] chars = Character.toChars(swapOrder);
291 swapOrder = chars[1];
292 return chars[0] << 16;
293 }
294 int order = swapOrder << 16;
295 swapOrder = 0;
296 return order;
297 }
298 int ch = text.previous();
299 if (ch == NormalizerBase.DONE) {
300 return NULLORDER;
301 }
302
303 int value = ordering.getUnicodeOrder(ch);
304
305 if (value == RuleBasedCollator.UNMAPPED) {
306 swapOrder = UNMAPPEDCHARVALUE;
307 return ch;
308 } else if (value >= RuleBasedCollator.CONTRACTCHARINDEX) {
309 value = prevContractChar(ch);
310 }
311 if (value >= RuleBasedCollator.EXPANDCHARINDEX) {
312 buffer = ordering.getExpandValueList(value);
313 expIndex = buffer.length;
314 value = buffer[--expIndex];
315 }
316
317 if (ordering.isSEAsianSwapping()) {
318 int vowel;
319 if (isThaiBaseConsonant(ch)) {
320 vowel = text.previous();
321 if (isThaiPreVowel(vowel)) {
322 buffer = makeReorderedBuffer(vowel, value, buffer, 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, false);
333 expIndex = buffer.length - 1;
334 value = buffer[expIndex];
335 } else {
336 text.next();
337 }
338 }
339 }
340
341 return strengthOrder(value);
342 }
343
344 /**
345 * Return the primary component of a collation element.
346 * @param order the collation element
347 * @return the element's primary component
348 */
349 public final static int primaryOrder(int order)
350 {
351 order &= RBCollationTables.PRIMARYORDERMASK;
352 return (order >>> RBCollationTables.PRIMARYORDERSHIFT);
353 }
354 /**
355 * Return the secondary component of a collation element.
356 * @param order the collation element
357 * @return the element's secondary component
358 */
359 public final static short secondaryOrder(int order)
360 {
361 order = order & RBCollationTables.SECONDARYORDERMASK;
362 return ((short)(order >> RBCollationTables.SECONDARYORDERSHIFT));
363 }
364 /**
365 * Return the tertiary component of a collation element.
366 * @param order the collation element
367 * @return the element's tertiary component
368 */
369 public final static short tertiaryOrder(int order)
370 {
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 {
381 int s = owner.getStrength();
382 if (s == Collator.PRIMARY)
383 {
384 order &= RBCollationTables.PRIMARYDIFFERENCEONLY;
385 } else if (s == Collator.SECONDARY)
386 {
387 order &= RBCollationTables.SECONDARYDIFFERENCEONLY;
388 }
389 return order;
390 }
391
392 /**
393 * Sets the iterator to point to the collation element corresponding to
394 * the specified character (the parameter is a CHARACTER offset in the
395 * original string, not an offset into its corresponding sequence of
396 * collation elements). The value returned by the next call to next()
397 * will be the collation element corresponding to the specified position
398 * in the text. If that position is in the middle of a contracting
399 * character sequence, the result of the next call to next() is the
400 * collation element for that sequence. This means that getOffset()
401 * is not guaranteed to return the same value as was passed to a preceding
402 * call to setOffset().
403 *
404 * @param newOffset The new character offset into the original text.
405 * @since 1.2
406 */
407 public void setOffset(int newOffset)
408 {
409 if (text != null) {
410 if (newOffset < text.getBeginIndex()
411 || newOffset >= text.getEndIndex()) {
412 text.setIndexOnly(newOffset);
413 } else {
414 int c = text.setIndex(newOffset);
415
416 // if the desired character isn't used in a contracting character
417 // sequence, bypass all the backing-up logic-- we're sitting on
418 // the right character already
419 if (ordering.usedInContractSeq(c)) {
420 // walk backwards through the string until we see a character
421 // that DOESN'T participate in a contracting character sequence
422 while (ordering.usedInContractSeq(c)) {
423 c = text.previous();
424 }
425 // now walk forward using this object's next() method until
426 // we pass the starting point and set our current position
427 // to the beginning of the last "character" before or at
428 // our starting position
429 int last = text.getIndex();
430 while (text.getIndex() <= newOffset) {
431 last = text.getIndex();
432 next();
433 }
434 text.setIndexOnly(last);
435 // we don't need this, since last is the last index
436 // that is the starting of the contraction which encompass
437 // newOffset
438 // text.previous();
439 }
440 }
441 }
442 buffer = null;
443 expIndex = 0;
444 swapOrder = 0;
445 }
446
447 /**
448 * Returns the character offset in the original text corresponding to the next
449 * collation element. (That is, getOffset() returns the position in the text
450 * corresponding to the collation element that will be returned by the next
451 * call to next().) This value will always be the index of the FIRST character
452 * corresponding to the collation element (a contracting character sequence is
453 * when two or more characters all correspond to the same collation element).
454 * This means if you do setOffset(x) followed immediately by getOffset(), getOffset()
455 * won't necessarily return x.
456 *
457 * @return The character offset in the original text corresponding to the collation
458 * element that will be returned by the next call to next().
459 * @since 1.2
460 */
461 public int getOffset()
462 {
463 return (text != null) ? text.getIndex() : 0;
464 }
465
466
467 /**
468 * Return the maximum length of any expansion sequences that end
469 * with the specified comparison order.
470 * @param order a collation order returned by previous or next.
471 * @return the maximum length of any expansion sequences ending
472 * with the specified order.
473 * @since 1.2
474 */
475 public int getMaxExpansion(int order)
476 {
477 return ordering.getMaxExpansion(order);
478 }
479
480 /**
481 * Set a new string over which to iterate.
482 *
483 * @param source the new source text
484 * @since 1.2
485 */
486 public void setText(String source)
487 {
488 buffer = null;
489 swapOrder = 0;
490 expIndex = 0;
491 NormalizerBase.Mode mode =
492 CollatorUtilities.toNormalizerMode(owner.getDecomposition());
493 if (text == null) {
494 text = new NormalizerBase(source, mode);
495 } else {
496 text.setMode(mode);
497 text.setText(source);
498 }
499 }
500
501 /**
502 * Set a new string over which to iterate.
503 *
504 * @param source the new source text.
505 * @since 1.2
506 */
507 public void setText(CharacterIterator source)
508 {
509 buffer = null;
510 swapOrder = 0;
511 expIndex = 0;
512 NormalizerBase.Mode mode =
513 CollatorUtilities.toNormalizerMode(owner.getDecomposition());
514 if (text == null) {
515 text = new NormalizerBase(source, mode);
516 } else {
517 text.setMode(mode);
518 text.setText(source);
519 }
520 }
521
522 //============================================================
523 // privates
524 //============================================================
525
526 /**
527 * Determine if a character is a Thai vowel (which sorts after
528 * its base consonant).
529 */
530 private final static boolean isThaiPreVowel(int ch) {
531 return (ch >= 0x0e40) && (ch <= 0x0e44);
532 }
533
534 /**
535 * Determine if a character is a Thai base consonant
536 */
537 private final static boolean isThaiBaseConsonant(int ch) {
538 return (ch >= 0x0e01) && (ch <= 0x0e2e);
539 }
540
541 /**
542 * Determine if a character is a Lao vowel (which sorts after
543 * its base consonant).
544 */
545 private final static boolean isLaoPreVowel(int ch) {
546 return (ch >= 0x0ec0) && (ch <= 0x0ec4);
547 }
548
549 /**
550 * Determine if a character is a Lao base consonant
551 */
552 private final static boolean isLaoBaseConsonant(int ch) {
553 return (ch >= 0x0e81) && (ch <= 0x0eae);
554 }
555
556 /**
557 * This method produces a buffer which contains the collation
558 * elements for the two characters, with colFirst's values preceding
559 * another character's. Presumably, the other character precedes colFirst
560 * in logical order (otherwise you wouldn't need this method would you?).
561 * The assumption is that the other char's value(s) have already been
562 * computed. If this char has a single element it is passed to this
563 * method as lastValue, and lastExpansion is null. If it has an
564 * expansion it is passed in lastExpansion, and colLastValue is ignored.
565 */
566 private int[] makeReorderedBuffer(int colFirst,
567 int lastValue,
568 int[] lastExpansion,
569 boolean forward) {
570
571 int[] result;
572
573 int firstValue = ordering.getUnicodeOrder(colFirst);
574 if (firstValue >= RuleBasedCollator.CONTRACTCHARINDEX) {
575 firstValue = forward? nextContractChar(colFirst) : prevContractChar(colFirst);
576 }
577
578 int[] firstExpansion = null;
579 if (firstValue >= RuleBasedCollator.EXPANDCHARINDEX) {
580 firstExpansion = ordering.getExpandValueList(firstValue);
581 }
582
583 if (!forward) {
584 int temp1 = firstValue;
585 firstValue = lastValue;
586 lastValue = temp1;
587 int[] temp2 = firstExpansion;
588 firstExpansion = lastExpansion;
589 lastExpansion = temp2;
590 }
591
592 if (firstExpansion == null && lastExpansion == null) {
593 result = new int [2];
594 result[0] = firstValue;
595 result[1] = lastValue;
596 }
597 else {
598 int firstLength = firstExpansion==null? 1 : firstExpansion.length;
599 int lastLength = lastExpansion==null? 1 : lastExpansion.length;
600 result = new int[firstLength + lastLength];
601
602 if (firstExpansion == null) {
603 result[0] = firstValue;
604 }
605 else {
606 System.arraycopy(firstExpansion, 0, result, 0, firstLength);
607 }
608
609 if (lastExpansion == null) {
610 result[firstLength] = lastValue;
611 }
612 else {
613 System.arraycopy(lastExpansion, 0, result, firstLength, lastLength);
614 }
615 }
616
617 return result;
618 }
619
620 /**
621 * Check if a comparison order is ignorable.
622 * @return true if a character is ignorable, false otherwise.
623 */
624 final static boolean isIgnorable(int order)
625 {
626 return ((primaryOrder(order) == 0) ? true : false);
627 }
628
629 /**
630 * Get the ordering priority of the next contracting character in the
631 * string.
632 * @param ch the starting character of a contracting character token
633 * @return the next contracting character's ordering. Returns NULLORDER
634 * if the end of string is reached.
635 */
636 private int nextContractChar(int ch)
637 {
638 // First get the ordering of this single character,
639 // which is always the first element in the list
640 Vector list = ordering.getContractValues(ch);
641 EntryPair pair = (EntryPair)list.firstElement();
642 int order = pair.value;
643
644 // find out the length of the longest contracting character sequence in the list.
645 // There's logic in the builder code to make sure the longest sequence is always
646 // the last.
647 pair = (EntryPair)list.lastElement();
648 int maxLength = pair.entryName.length();
649
650 // (the Normalizer is cloned here so that the seeking we do in the next loop
651 // won't affect our real position in the text)
652 NormalizerBase tempText = (NormalizerBase)text.clone();
653
654 // extract the next maxLength characters in the string (we have to do this using the
655 // Normalizer to ensure that our offsets correspond to those the rest of the
656 // iterator is using) and store it in "fragment".
657 tempText.previous();
658 key.setLength(0);
659 int c = tempText.next();
660 while (maxLength > 0 && c != NormalizerBase.DONE) {
661 if (Character.isSupplementaryCodePoint(c)) {
662 key.append(Character.toChars(c));
663 maxLength -= 2;
664 } else {
665 key.append((char)c);
666 --maxLength;
667 }
668 c = tempText.next();
669 }
670 String fragment = key.toString();
671 // now that we have that fragment, iterate through this list looking for the
672 // longest sequence that matches the characters in the actual text. (maxLength
673 // is used here to keep track of the length of the longest sequence)
674 // Upon exit from this loop, maxLength will contain the length of the matching
675 // sequence and order will contain the collation-element value corresponding
676 // to this sequence
677 maxLength = 1;
678 for (int i = list.size() - 1; i > 0; i--) {
679 pair = (EntryPair)list.elementAt(i);
680 if (!pair.fwd)
681 continue;
682
683 if (fragment.startsWith(pair.entryName) && pair.entryName.length()
684 > maxLength) {
685 maxLength = pair.entryName.length();
686 order = pair.value;
687 }
688 }
689
690 // seek our current iteration position to the end of the matching sequence
691 // and return the appropriate collation-element value (if there was no matching
692 // sequence, we're already seeked to the right position and order already contains
693 // the correct collation-element value for the single character)
694 while (maxLength > 1) {
695 c = text.next();
696 maxLength -= Character.charCount(c);
697 }
698 return order;
699 }
700
701 /**
702 * Get the ordering priority of the previous contracting character in the
703 * string.
704 * @param ch the starting character of a contracting character token
705 * @return the next contracting character's ordering. Returns NULLORDER
706 * if the end of string is reached.
707 */
708 private int prevContractChar(int ch)
709 {
710 // This function is identical to nextContractChar(), except that we've
711 // switched things so that the next() and previous() calls on the Normalizer
712 // are switched and so that we skip entry pairs with the fwd flag turned on
713 // rather than off. Notice that we still use append() and startsWith() when
714 // working on the fragment. This is because the entry pairs that are used
715 // in reverse iteration have their names reversed already.
716 Vector list = ordering.getContractValues(ch);
717 EntryPair pair = (EntryPair)list.firstElement();
718 int order = pair.value;
719
720 pair = (EntryPair)list.lastElement();
721 int maxLength = pair.entryName.length();
722
723 NormalizerBase tempText = (NormalizerBase)text.clone();
724
725 tempText.next();
726 key.setLength(0);
727 int c = tempText.previous();
728 while (maxLength > 0 && c != NormalizerBase.DONE) {
729 if (Character.isSupplementaryCodePoint(c)) {
730 key.append(Character.toChars(c));
731 maxLength -= 2;
732 } else {
733 key.append((char)c);
734 --maxLength;
735 }
736 c = tempText.previous();
737 }
738 String fragment = key.toString();
739
740 maxLength = 1;
741 for (int i = list.size() - 1; i > 0; i--) {
742 pair = (EntryPair)list.elementAt(i);
743 if (pair.fwd)
744 continue;
745
746 if (fragment.startsWith(pair.entryName) && pair.entryName.length()
747 > maxLength) {
748 maxLength = pair.entryName.length();
749 order = pair.value;
750 }
751 }
752
753 while (maxLength > 1) {
754 c = text.previous();
755 maxLength -= Character.charCount(c);
756 }
757 return order;
758 }
759
760 final static int UNMAPPEDCHARVALUE = 0x7FFF0000;
761
762 private NormalizerBase text = null;
763 private int[] buffer = null;
764 private int expIndex = 0;
765 private StringBuffer key = new StringBuffer(5);
766 private int swapOrder = 0;
767 private RBCollationTables ordering;
768 private RuleBasedCollator owner;
769 }