1. /*
  2. * @(#)CollationElementIterator.java 1.45 03/01/27
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. /*
  8. * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  9. * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
  10. *
  11. * The original version of this source code and documentation is copyrighted
  12. * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  13. * materials are provided under terms of a License Agreement between Taligent
  14. * and Sun. This technology is protected by multiple US and International
  15. * patents. This notice and attribution to Taligent may not be removed.
  16. * Taligent is a registered trademark of Taligent, Inc.
  17. *
  18. */
  19. package java.text;
  20. import java.lang.Character;
  21. import java.util.Vector;
  22. import sun.text.Normalizer;
  23. import sun.text.NormalizerUtilities;
  24. /**
  25. * The <code>CollationElementIterator</code> class is used as an iterator
  26. * to walk through each character of an international string. Use the iterator
  27. * to return the ordering priority of the positioned character. The ordering
  28. * priority of a character, which we refer to as a key, defines how a character
  29. * is collated in the given collation object.
  30. *
  31. * <p>
  32. * For example, consider the following in Spanish:
  33. * <blockquote>
  34. * <pre>
  35. * "ca" -> the first key is key('c') and second key is key('a').
  36. * "cha" -> the first key is key('ch') and second key is key('a').
  37. * </pre>
  38. * </blockquote>
  39. * And in German,
  40. * <blockquote>
  41. * <pre>
  42. * "\u00e4b"-> the first key is key('a'), the second key is key('e'), and
  43. * the third key is key('b').
  44. * </pre>
  45. * </blockquote>
  46. * The key of a character is an integer composed of primary order(short),
  47. * secondary order(byte), and tertiary order(byte). Java strictly defines
  48. * the size and signedness of its primitive data types. Therefore, the static
  49. * functions <code>primaryOrder</code>, <code>secondaryOrder</code>, and
  50. * <code>tertiaryOrder</code> return <code>int</code>, <code>short</code>,
  51. * and <code>short</code> respectively to ensure the correctness of the key
  52. * value.
  53. *
  54. * <p>
  55. * Example of the iterator usage,
  56. * <blockquote>
  57. * <pre>
  58. *
  59. * String testString = "This is a test";
  60. * RuleBasedCollator ruleBasedCollator = (RuleBasedCollator)Collator.getInstance();
  61. * CollationElementIterator collationElementIterator = ruleBasedCollator.getCollationElementIterator(testString);
  62. * int primaryOrder = CollationElementIterator.primaryOrder(collationElementIterator.next());
  63. * </pre>
  64. * </blockquote>
  65. *
  66. * <p>
  67. * <code>CollationElementIterator.next</code> returns the collation order
  68. * of the next character. A collation order consists of primary order,
  69. * secondary order and tertiary order. The data type of the collation
  70. * order is <strong>int</strong>. The first 16 bits of a collation order
  71. * is its primary order; the next 8 bits is the secondary order and the
  72. * last 8 bits is the tertiary order.
  73. *
  74. * @see Collator
  75. * @see RuleBasedCollator
  76. * @version 1.24 07/27/98
  77. * @author Helena Shih, Laura Werner, Richard Gillam
  78. */
  79. public final class CollationElementIterator
  80. {
  81. /**
  82. * Null order which indicates the end of string is reached by the
  83. * cursor.
  84. */
  85. public final static int NULLORDER = 0xffffffff;
  86. /**
  87. * CollationElementIterator constructor. This takes the source string and
  88. * the collation object. The cursor will walk thru the source string based
  89. * on the predefined collation rules. If the source string is empty,
  90. * NULLORDER will be returned on the calls to next().
  91. * @param sourceText the source string.
  92. * @param order the collation object.
  93. */
  94. CollationElementIterator(String sourceText, RuleBasedCollator owner) {
  95. this.owner = owner;
  96. ordering = owner.getTables();
  97. if ( sourceText.length() != 0 ) {
  98. Normalizer.Mode mode =
  99. NormalizerUtilities.toNormalizerMode(owner.getDecomposition());
  100. text = new Normalizer(sourceText, mode);
  101. }
  102. }
  103. /**
  104. * CollationElementIterator constructor. This takes the source string and
  105. * the collation object. The cursor will walk thru the source string based
  106. * on the predefined collation rules. If the source string is empty,
  107. * NULLORDER will be returned on the calls to next().
  108. * @param sourceText the source string.
  109. * @param order the collation object.
  110. */
  111. CollationElementIterator(CharacterIterator sourceText, RuleBasedCollator owner) {
  112. this.owner = owner;
  113. ordering = owner.getTables();
  114. Normalizer.Mode mode =
  115. NormalizerUtilities.toNormalizerMode(owner.getDecomposition());
  116. text = new Normalizer(sourceText, mode);
  117. }
  118. /**
  119. * Resets the cursor to the beginning of the string. The next call
  120. * to next() will return the first collation element in the string.
  121. */
  122. public void reset()
  123. {
  124. if (text != null) {
  125. text.reset();
  126. Normalizer.Mode mode =
  127. NormalizerUtilities.toNormalizerMode(owner.getDecomposition());
  128. text.setMode(mode);
  129. }
  130. buffer = null;
  131. expIndex = 0;
  132. swapOrder = 0;
  133. }
  134. /**
  135. * Get the next collation element in the string. <p>This iterator iterates
  136. * over a sequence of collation elements that were built from the string.
  137. * Because there isn't necessarily a one-to-one mapping from characters to
  138. * collation elements, this doesn't mean the same thing as "return the
  139. * collation element [or ordering priority] of the next character in the
  140. * string".</p>
  141. * <p>This function returns the collation element that the iterator is currently
  142. * pointing to and then updates the internal pointer to point to the next element.
  143. * previous() updates the pointer first and then returns the element. This
  144. * means that when you change direction while iterating (i.e., call next() and
  145. * then call previous(), or call previous() and then call next()), you'll get
  146. * back the same element twice.</p>
  147. */
  148. public int next()
  149. {
  150. if (text == null) {
  151. return NULLORDER;
  152. }
  153. Normalizer.Mode textMode = text.getMode();
  154. // convert the owner's mode to something the Normalizer understands
  155. Normalizer.Mode ownerMode =
  156. NormalizerUtilities.toNormalizerMode(owner.getDecomposition());
  157. if (textMode != ownerMode) {
  158. text.setMode(ownerMode);
  159. }
  160. // if buffer contains any decomposed char values
  161. // return their strength orders before continuing in
  162. // the the Normalizer's CharacterIterator.
  163. if (buffer != null) {
  164. if (expIndex < buffer.length) {
  165. return strengthOrder(buffer[expIndex++]);
  166. } else {
  167. buffer = null;
  168. expIndex = 0;
  169. }
  170. } else if (swapOrder != 0) {
  171. int order = swapOrder << 16;
  172. swapOrder = 0;
  173. return order;
  174. }
  175. char ch = text.next();
  176. // are we at the end of Normalizer's text?
  177. if (ch == Normalizer.DONE) {
  178. return NULLORDER;
  179. }
  180. int value = ordering.getUnicodeOrder(ch);
  181. if (value == RuleBasedCollator.UNMAPPED) {
  182. swapOrder = ch;
  183. return UNMAPPEDCHARVALUE;
  184. }
  185. else if (value >= RuleBasedCollator.CONTRACTCHARINDEX) {
  186. value = nextContractChar(ch);
  187. }
  188. if (value >= RuleBasedCollator.EXPANDCHARINDEX) {
  189. buffer = ordering.getExpandValueList(value);
  190. expIndex = 0;
  191. value = buffer[expIndex++];
  192. }
  193. if (ordering.isSEAsianSwapping()) {
  194. char consonant;
  195. if (isThaiPreVowel(ch)) {
  196. consonant = text.next();
  197. if (isThaiBaseConsonant(consonant)) {
  198. buffer = makeReorderedBuffer(consonant, value, buffer, true);
  199. value = buffer[0];
  200. expIndex = 1;
  201. } else {
  202. text.previous();
  203. }
  204. }
  205. if (isLaoPreVowel(ch)) {
  206. consonant = text.next();
  207. if (isLaoBaseConsonant(consonant)) {
  208. buffer = makeReorderedBuffer(consonant, value, buffer, true);
  209. value = buffer[0];
  210. expIndex = 1;
  211. } else {
  212. text.previous();
  213. }
  214. }
  215. }
  216. return strengthOrder(value);
  217. }
  218. /**
  219. * Get the previous collation element in the string. <p>This iterator iterates
  220. * over a sequence of collation elements that were built from the string.
  221. * Because there isn't necessarily a one-to-one mapping from characters to
  222. * collation elements, this doesn't mean the same thing as "return the
  223. * collation element [or ordering priority] of the previous character in the
  224. * string".</p>
  225. * <p>This function updates the iterator's internal pointer to point to the
  226. * collation element preceding the one it's currently pointing to and then
  227. * returns that element, while next() returns the current element and then
  228. * updates the pointer. This means that when you change direction while
  229. * iterating (i.e., call next() and then call previous(), or call previous()
  230. * and then call next()), you'll get back the same element twice.</p>
  231. * @since 1.2
  232. */
  233. public int previous()
  234. {
  235. if (text == null) {
  236. return NULLORDER;
  237. }
  238. Normalizer.Mode textMode = text.getMode();
  239. // convert the owner's mode to something the Normalizer understands
  240. Normalizer.Mode ownerMode =
  241. NormalizerUtilities.toNormalizerMode(owner.getDecomposition());
  242. if (textMode != ownerMode) {
  243. text.setMode(ownerMode);
  244. }
  245. if (buffer != null) {
  246. if (expIndex > 0) {
  247. return strengthOrder(buffer[--expIndex]);
  248. } else {
  249. buffer = null;
  250. expIndex = 0;
  251. }
  252. } else if (swapOrder != 0) {
  253. int order = swapOrder << 16;
  254. swapOrder = 0;
  255. return order;
  256. }
  257. char ch = text.previous();
  258. if (ch == Normalizer.DONE) {
  259. return NULLORDER;
  260. }
  261. int value = ordering.getUnicodeOrder(ch);
  262. if (value == RuleBasedCollator.UNMAPPED) {
  263. swapOrder = UNMAPPEDCHARVALUE;
  264. return ch;
  265. } else if (value >= RuleBasedCollator.CONTRACTCHARINDEX) {
  266. value = prevContractChar(ch);
  267. }
  268. if (value >= RuleBasedCollator.EXPANDCHARINDEX) {
  269. buffer = ordering.getExpandValueList(value);
  270. expIndex = buffer.length;
  271. value = buffer[--expIndex];
  272. }
  273. if (ordering.isSEAsianSwapping()) {
  274. char vowel;
  275. if (isThaiBaseConsonant(ch)) {
  276. vowel = text.previous();
  277. if (isThaiPreVowel(vowel)) {
  278. buffer = makeReorderedBuffer(vowel, value, buffer, false);
  279. expIndex = buffer.length - 1;
  280. value = buffer[expIndex];
  281. } else {
  282. text.next();
  283. }
  284. }
  285. if (isLaoBaseConsonant(ch)) {
  286. vowel = text.previous();
  287. if (isLaoPreVowel(vowel)) {
  288. buffer = makeReorderedBuffer(vowel, value, buffer, false);
  289. expIndex = buffer.length - 1;
  290. value = buffer[expIndex];
  291. } else {
  292. text.next();
  293. }
  294. }
  295. }
  296. return strengthOrder(value);
  297. }
  298. /**
  299. * Return the primary component of a collation element.
  300. * @param order the collation element
  301. * @return the element's primary component
  302. */
  303. public final static int primaryOrder(int order)
  304. {
  305. order &= RBCollationTables.PRIMARYORDERMASK;
  306. return (order >>> RBCollationTables.PRIMARYORDERSHIFT);
  307. }
  308. /**
  309. * Return the secondary component of a collation element.
  310. * @param order the collation element
  311. * @return the element's secondary component
  312. */
  313. public final static short secondaryOrder(int order)
  314. {
  315. order = order & RBCollationTables.SECONDARYORDERMASK;
  316. return ((short)(order >> RBCollationTables.SECONDARYORDERSHIFT));
  317. }
  318. /**
  319. * Return the tertiary component of a collation element.
  320. * @param order the collation element
  321. * @return the element's tertiary component
  322. */
  323. public final static short tertiaryOrder(int order)
  324. {
  325. return ((short)(order &= RBCollationTables.TERTIARYORDERMASK));
  326. }
  327. /**
  328. * Get the comparison order in the desired strength. Ignore the other
  329. * differences.
  330. * @param order The order value
  331. */
  332. final int strengthOrder(int order)
  333. {
  334. int s = owner.getStrength();
  335. if (s == Collator.PRIMARY)
  336. {
  337. order &= RBCollationTables.PRIMARYDIFFERENCEONLY;
  338. } else if (s == Collator.SECONDARY)
  339. {
  340. order &= RBCollationTables.SECONDARYDIFFERENCEONLY;
  341. }
  342. return order;
  343. }
  344. /**
  345. * Sets the iterator to point to the collation element corresponding to
  346. * the specified character (the parameter is a CHARACTER offset in the
  347. * original string, not an offset into its corresponding sequence of
  348. * collation elements). The value returned by the next call to next()
  349. * will be the collation element corresponding to the specified position
  350. * in the text. If that position is in the middle of a contracting
  351. * character sequence, the result of the next call to next() is the
  352. * collation element for that sequence. This means that getOffset()
  353. * is not guaranteed to return the same value as was passed to a preceding
  354. * call to setOffset().
  355. *
  356. * @param newOffset The new character offset into the original text.
  357. * @since 1.2
  358. */
  359. public void setOffset(int newOffset)
  360. {
  361. if (text != null) {
  362. if (newOffset < text.getBeginIndex()
  363. || newOffset >= text.getEndIndex()) {
  364. text.setIndexOnly(newOffset);
  365. } else {
  366. char c = text.setIndex(newOffset);
  367. // if the desired character isn't used in a contracting character
  368. // sequence, bypass all the backing-up logic-- we're sitting on
  369. // the right character already
  370. if (ordering.usedInContractSeq(c)) {
  371. // walk backwards through the string until we see a character
  372. // that DOESN'T participate in a contracting character sequence
  373. while (ordering.usedInContractSeq(c)) {
  374. c = text.previous();
  375. }
  376. // now walk forward using this object's next() method until
  377. // we pass the starting point and set our current position
  378. // to the beginning of the last "character" before or at
  379. // our starting position
  380. int last = text.getIndex();
  381. while (text.getIndex() <= newOffset) {
  382. last = text.getIndex();
  383. next();
  384. }
  385. text.setIndexOnly(last);
  386. // we don't need this, since last is the last index
  387. // that is the starting of the contraction which encompass
  388. // newOffset
  389. // text.previous();
  390. }
  391. }
  392. }
  393. buffer = null;
  394. expIndex = 0;
  395. swapOrder = 0;
  396. }
  397. /**
  398. * Returns the character offset in the original text corresponding to the next
  399. * collation element. (That is, getOffset() returns the position in the text
  400. * corresponding to the collation element that will be returned by the next
  401. * call to next().) This value will always be the index of the FIRST character
  402. * corresponding to the collation element (a contracting character sequence is
  403. * when two or more characters all correspond to the same collation element).
  404. * This means if you do setOffset(x) followed immediately by getOffset(), getOffset()
  405. * won't necessarily return x.
  406. *
  407. * @return The character offset in the original text corresponding to the collation
  408. * element that will be returned by the next call to next().
  409. * @since 1.2
  410. */
  411. public int getOffset()
  412. {
  413. return (text != null) ? text.getIndex() : 0;
  414. }
  415. /**
  416. * Return the maximum length of any expansion sequences that end
  417. * with the specified comparison order.
  418. * @param order a collation order returned by previous or next.
  419. * @return the maximum length of any expansion sequences ending
  420. * with the specified order.
  421. * @since 1.2
  422. */
  423. public int getMaxExpansion(int order)
  424. {
  425. return ordering.getMaxExpansion(order);
  426. }
  427. /**
  428. * Set a new string over which to iterate.
  429. *
  430. * @param source the new source text
  431. * @since 1.2
  432. */
  433. public void setText(String source)
  434. {
  435. buffer = null;
  436. swapOrder = 0;
  437. expIndex = 0;
  438. Normalizer.Mode mode =
  439. NormalizerUtilities.toNormalizerMode(owner.getDecomposition());
  440. if (text == null) {
  441. text = new Normalizer(source, mode);
  442. } else {
  443. text.setMode(mode);
  444. text.setText(source);
  445. }
  446. }
  447. /**
  448. * Set a new string over which to iterate.
  449. *
  450. * @param source the new source text.
  451. * @since 1.2
  452. */
  453. public void setText(CharacterIterator source)
  454. {
  455. buffer = null;
  456. swapOrder = 0;
  457. expIndex = 0;
  458. Normalizer.Mode mode =
  459. NormalizerUtilities.toNormalizerMode(owner.getDecomposition());
  460. if (text == null) {
  461. text = new Normalizer(source, mode);
  462. } else {
  463. text.setMode(mode);
  464. text.setText(source);
  465. }
  466. }
  467. //============================================================
  468. // privates
  469. //============================================================
  470. /**
  471. * Determine if a character is a Thai vowel (which sorts after
  472. * its base consonant).
  473. */
  474. private final static boolean isThaiPreVowel(char ch) {
  475. return (ch >= '\u0e40') && (ch <= '\u0e44');
  476. }
  477. /**
  478. * Determine if a character is a Thai base consonant
  479. */
  480. private final static boolean isThaiBaseConsonant(char ch) {
  481. return (ch >= '\u0e01') && (ch <= '\u0e2e');
  482. }
  483. /**
  484. * Determine if a character is a Lao vowel (which sorts after
  485. * its base consonant).
  486. */
  487. private final static boolean isLaoPreVowel(char ch) {
  488. return (ch >= '\u0ec0') && (ch <= '\u0ec4');
  489. }
  490. /**
  491. * Determine if a character is a Lao base consonant
  492. */
  493. private final static boolean isLaoBaseConsonant(char ch) {
  494. return (ch >= '\u0e81') && (ch <= '\u0eae');
  495. }
  496. /**
  497. * This method produces a buffer which contains the collation
  498. * elements for the two characters, with colFirst's values preceding
  499. * another character's. Presumably, the other character precedes colFirst
  500. * in logical order (otherwise you wouldn't need this method would you?).
  501. * The assumption is that the other char's value(s) have already been
  502. * computed. If this char has a single element it is passed to this
  503. * method as lastValue, and lastExpansion is null. If it has an
  504. * expansion it is passed in lastExpansion, and colLastValue is ignored.
  505. */
  506. private int[] makeReorderedBuffer(char colFirst,
  507. int lastValue,
  508. int[] lastExpansion,
  509. boolean forward) {
  510. int[] result;
  511. int firstValue = ordering.getUnicodeOrder(colFirst);
  512. if (firstValue >= RuleBasedCollator.CONTRACTCHARINDEX) {
  513. firstValue = forward? nextContractChar(colFirst) : prevContractChar(colFirst);
  514. }
  515. int[] firstExpansion = null;
  516. if (firstValue >= RuleBasedCollator.EXPANDCHARINDEX) {
  517. firstExpansion = ordering.getExpandValueList(firstValue);
  518. }
  519. if (!forward) {
  520. int temp1 = firstValue;
  521. firstValue = lastValue;
  522. lastValue = temp1;
  523. int[] temp2 = firstExpansion;
  524. firstExpansion = lastExpansion;
  525. lastExpansion = temp2;
  526. }
  527. if (firstExpansion == null && lastExpansion == null) {
  528. result = new int [2];
  529. result[0] = firstValue;
  530. result[1] = lastValue;
  531. }
  532. else {
  533. int firstLength = firstExpansion==null? 1 : firstExpansion.length;
  534. int lastLength = lastExpansion==null? 1 : lastExpansion.length;
  535. result = new int[firstLength + lastLength];
  536. if (firstExpansion == null) {
  537. result[0] = firstValue;
  538. }
  539. else {
  540. System.arraycopy(firstExpansion, 0, result, 0, firstLength);
  541. }
  542. if (lastExpansion == null) {
  543. result[firstLength] = lastValue;
  544. }
  545. else {
  546. System.arraycopy(lastExpansion, 0, result, firstLength, lastLength);
  547. }
  548. }
  549. return result;
  550. }
  551. /**
  552. * Check if a comparison order is ignorable.
  553. * @return true if a character is ignorable, false otherwise.
  554. */
  555. final static boolean isIgnorable(int order)
  556. {
  557. return ((primaryOrder(order) == 0) ? true : false);
  558. }
  559. /**
  560. * Get the ordering priority of the next contracting character in the
  561. * string.
  562. * @param ch the starting character of a contracting character token
  563. * @return the next contracting character's ordering. Returns NULLORDER
  564. * if the end of string is reached.
  565. */
  566. private int nextContractChar(char ch)
  567. {
  568. // First get the ordering of this single character,
  569. // which is always the first element in the list
  570. Vector list = ordering.getContractValues(ch);
  571. EntryPair pair = (EntryPair)list.firstElement();
  572. int order = pair.value;
  573. // find out the length of the longest contracting character sequence in the list.
  574. // There's logic in the builder code to make sure the longest sequence is always
  575. // the last.
  576. pair = (EntryPair)list.lastElement();
  577. int maxLength = pair.entryName.length();
  578. // (the Normalizer is cloned here so that the seeking we do in the next loop
  579. // won't affect our real position in the text)
  580. Normalizer tempText = (Normalizer)text.clone();
  581. // extract the next maxLength characters in the string (we have to do this using the
  582. // Normalizer to ensure that our offsets correspond to those the rest of the
  583. // iterator is using) and store it in "fragment".
  584. tempText.previous();
  585. key.setLength(0);
  586. char c = tempText.next();
  587. while (maxLength > 0 && c != Normalizer.DONE) {
  588. key.append(c);
  589. --maxLength;
  590. c = tempText.next();
  591. }
  592. String fragment = key.toString();
  593. // now that we have that fragment, iterate through this list looking for the
  594. // longest sequence that matches the characters in the actual text. (maxLength
  595. // is used here to keep track of the length of the longest sequence)
  596. // Upon exit from this loop, maxLength will contain the length of the matching
  597. // sequence and order will contain the collation-element value corresponding
  598. // to this sequence
  599. maxLength = 1;
  600. for (int i = list.size() - 1; i > 0; i--) {
  601. pair = (EntryPair)list.elementAt(i);
  602. if (!pair.fwd)
  603. continue;
  604. if (fragment.startsWith(pair.entryName) && pair.entryName.length()
  605. > maxLength) {
  606. maxLength = pair.entryName.length();
  607. order = pair.value;
  608. }
  609. }
  610. // seek our current iteration position to the end of the matching sequence
  611. // and return the appropriate collation-element value (if there was no matching
  612. // sequence, we're already seeked to the right position and order already contains
  613. // the correct collation-element value for the single character)
  614. while (maxLength > 1) {
  615. text.next();
  616. --maxLength;
  617. }
  618. return order;
  619. }
  620. /**
  621. * Get the ordering priority of the previous contracting character in the
  622. * string.
  623. * @param ch the starting character of a contracting character token
  624. * @return the next contracting character's ordering. Returns NULLORDER
  625. * if the end of string is reached.
  626. */
  627. private int prevContractChar(char ch)
  628. {
  629. // This function is identical to nextContractChar(), except that we've
  630. // switched things so that the next() and previous() calls on the Normalizer
  631. // are switched and so that we skip entry pairs with the fwd flag turned on
  632. // rather than off. Notice that we still use append() and startsWith() when
  633. // working on the fragment. This is because the entry pairs that are used
  634. // in reverse iteration have their names reversed already.
  635. Vector list = ordering.getContractValues(ch);
  636. EntryPair pair = (EntryPair)list.firstElement();
  637. int order = pair.value;
  638. pair = (EntryPair)list.lastElement();
  639. int maxLength = pair.entryName.length();
  640. Normalizer tempText = (Normalizer)text.clone();
  641. tempText.next();
  642. key.setLength(0);
  643. char c = tempText.previous();
  644. while (maxLength > 0 && c != Normalizer.DONE) {
  645. key.append(c);
  646. --maxLength;
  647. c = tempText.previous();
  648. }
  649. String fragment = key.toString();
  650. maxLength = 1;
  651. for (int i = list.size() - 1; i > 0; i--) {
  652. pair = (EntryPair)list.elementAt(i);
  653. if (pair.fwd)
  654. continue;
  655. if (fragment.startsWith(pair.entryName) && pair.entryName.length()
  656. > maxLength) {
  657. maxLength = pair.entryName.length();
  658. order = pair.value;
  659. }
  660. }
  661. while (maxLength > 1) {
  662. text.previous();
  663. --maxLength;
  664. }
  665. return order;
  666. }
  667. final static int UNMAPPEDCHARVALUE = 0x7FFF0000;
  668. private Normalizer text = null;
  669. private int[] buffer = null;
  670. private int expIndex = 0;
  671. private StringBuffer key = new StringBuffer(5);
  672. private int swapOrder = 0;
  673. private RBCollationTables ordering;
  674. private RuleBasedCollator owner;
  675. }