]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_4_2-src/main/classes/collate/src/com/ibm/icu/text/CollationElementIterator.java
go
[Dictionary.git] / jars / icu4j-4_4_2-src / main / classes / collate / src / com / ibm / icu / text / CollationElementIterator.java
1 /**\r
2 *******************************************************************************\r
3 * Copyright (C) 1996-2010, International Business Machines Corporation and    *\r
4 * others. All Rights Reserved.                                                *\r
5 *******************************************************************************\r
6 *\r
7 *\r
8 *******************************************************************************\r
9 */\r
10 package com.ibm.icu.text;\r
11 \r
12 /***\r
13  * import java.text.StringCharacterIterator;\r
14  * import java.text.CharacterIterator;\r
15  */\r
16 import java.text.CharacterIterator;\r
17 import java.util.MissingResourceException;\r
18 \r
19 import com.ibm.icu.impl.CharacterIteratorWrapper;\r
20 import com.ibm.icu.impl.ICUDebug;\r
21 import com.ibm.icu.impl.Norm2AllModes;\r
22 import com.ibm.icu.impl.Normalizer2Impl;\r
23 import com.ibm.icu.impl.StringUCharacterIterator;\r
24 import com.ibm.icu.impl.UCharacterProperty;\r
25 import com.ibm.icu.lang.UCharacter;\r
26 \r
27 /**\r
28  * <p><code>CollationElementIterator</code> is an iterator created by\r
29  * a RuleBasedCollator to walk through a string. The return result of\r
30  * each iteration is a 32-bit collation element that defines the\r
31  * ordering priority of the next character or sequence of characters\r
32  * in the source string.</p>\r
33  *\r
34  * <p>For illustration, consider the following in Spanish:\r
35  * <blockquote>\r
36  * <pre>\r
37  * "ca" -> the first collation element is collation_element('c') and second\r
38  *         collation element is collation_element('a').\r
39  *\r
40  * Since "ch" in Spanish sorts as one entity, the below example returns one\r
41  * collation element for the two characters 'c' and 'h'\r
42  *\r
43  * "cha" -> the first collation element is collation_element('ch') and second\r
44  *          collation element is collation_element('a').\r
45  * </pre>\r
46  * </blockquote>\r
47  * And in German,\r
48  * <blockquote>\r
49  * <pre>\r
50  * Since the character '&#230;' is a composed character of 'a' and 'e', the\r
51  * iterator returns two collation elements for the single character '&#230;'\r
52  *\r
53  * "&#230;b" -> the first collation element is collation_element('a'), the\r
54  *              second collation element is collation_element('e'), and the\r
55  *              third collation element is collation_element('b').\r
56  * </pre>\r
57  * </blockquote>\r
58  * </p>\r
59  *\r
60  * <p>For collation ordering comparison, the collation element results\r
61  * can not be compared simply by using basic arithmetric operators,\r
62  * e.g. &lt;, == or &gt;, further processing has to be done. Details\r
63  * can be found in the ICU\r
64  * <a href="http://www.icu-project.org/userguide/Collate_ServiceArchitecture.html">\r
65  * user guide</a>. An example of using the CollationElementIterator\r
66  * for collation ordering comparison is the class\r
67  * <a href=StringSearch.html> com.ibm.icu.text.StringSearch</a>.</p>\r
68  *\r
69  * <p>To construct a CollationElementIterator object, users\r
70  * call the method getCollationElementIterator() on a\r
71  * RuleBasedCollator that defines the desired sorting order.</p>\r
72  *\r
73  * <p> Example:\r
74  * <blockquote>\r
75  * <pre>\r
76  *  String testString = "This is a test";\r
77  *  RuleBasedCollator rbc = new RuleBasedCollator("&amp;a&lt;b");\r
78  *  CollationElementIterator iterator = rbc.getCollationElementIterator(testString);\r
79  *  int primaryOrder = iterator.IGNORABLE;\r
80  *  while (primaryOrder != iterator.NULLORDER) {\r
81  *      int order = iterator.next();\r
82  *      if (order != iterator.IGNORABLE &&\r
83  *          order != iterator.NULLORDER) {\r
84  *          // order is valid, not ignorable and we have not passed the end\r
85  *          // of the iteration, we do something\r
86  *          primaryOrder = CollationElementIterator.primaryOrder(order);\r
87  *          System.out.println("Next primary order 0x" +\r
88  *                             Integer.toHexString(primaryOrder));\r
89  *      }\r
90  *  }\r
91  * </pre>\r
92  * </blockquote>\r
93  * </p>\r
94  * <p>\r
95  * This class is not subclassable\r
96  * </p>\r
97  * @see Collator\r
98  * @see RuleBasedCollator\r
99  * @see StringSearch\r
100  * @author Syn Wee Quek\r
101  * @stable ICU 2.8\r
102  */\r
103 public final class CollationElementIterator\r
104 {\r
105   \r
106     \r
107     // public data members --------------------------------------------------\r
108 \r
109     /**\r
110      * <p>This constant is returned by the iterator in the methods\r
111      * next() and previous() when the end or the beginning of the\r
112      * source string has been reached, and there are no more valid\r
113      * collation elements to return.</p>\r
114      *\r
115      * <p>See class documentation for an example of use.</p>\r
116      * @stable ICU 2.8\r
117      * @see #next\r
118      * @see #previous */\r
119     public final static int NULLORDER = 0xffffffff;\r
120 \r
121     /**\r
122      * <p>This constant is returned by the iterator in the methods\r
123      * next() and previous() when a collation element result is to be\r
124      * ignored.</p>\r
125      *\r
126      * <p>See class documentation for an example of use.</p>\r
127      * @stable ICU 2.8\r
128      * @see #next\r
129      * @see #previous */\r
130     public static final int IGNORABLE = 0;\r
131 \r
132     // public methods -------------------------------------------------------\r
133 \r
134     // public getters -------------------------------------------------------\r
135 \r
136     /**\r
137      * <p>Returns the character offset in the source string\r
138      * corresponding to the next collation element. I.e., getOffset()\r
139      * returns the position in the source string corresponding to the\r
140      * collation element that will be returned by the next call to\r
141      * next(). This value could be any of:\r
142      * <ul>\r
143      * <li> The index of the <b>first</b> character corresponding to\r
144      * the next collation element. (This means that if\r
145      * <code>setOffset(offset)</code> sets the index in the middle of\r
146      * a contraction, <code>getOffset()</code> returns the index of\r
147      * the first character in the contraction, which may not be equal\r
148      * to the original offset that was set. Hence calling getOffset()\r
149      * immediately after setOffset(offset) does not guarantee that the\r
150      * original offset set will be returned.)\r
151      * <li> If normalization is on, the index of the <b>immediate</b>\r
152      * subsequent character, or composite character with the first\r
153      * character, having a combining class of 0.\r
154      * <li> The length of the source string, if iteration has reached\r
155      * the end.\r
156      *</ul>\r
157      * </p>\r
158      * @return The character offset in the source string corresponding to the\r
159      *         collation element that will be returned by the next call to\r
160      *         next().\r
161      * @stable ICU 2.8\r
162      */\r
163     public int getOffset()\r
164     {\r
165         if (m_bufferOffset_ != -1) {\r
166             if (m_isForwards_) {\r
167                 return m_FCDLimit_;\r
168             }\r
169             return m_FCDStart_;\r
170         }\r
171         return m_source_.getIndex();\r
172     }\r
173 \r
174 \r
175     /**\r
176      * <p> Returns the maximum length of any expansion sequence that ends with\r
177      * the specified collation element. If there is no expansion with this\r
178      * collation element as the last element, returns 1.\r
179      * </p>\r
180      * @param ce a collation element returned by previous() or next().\r
181      * @return the maximum length of any expansion sequence ending\r
182      *         with the specified collation element.\r
183      * @stable ICU 2.8\r
184      */\r
185     public int getMaxExpansion(int ce)\r
186     {\r
187         int start = 0;\r
188         int limit = m_collator_.m_expansionEndCE_.length;\r
189         long unsignedce = ce & 0xFFFFFFFFl;\r
190         while (start < limit - 1) {\r
191             int mid = start + ((limit - start) >> 1);\r
192             long midce = m_collator_.m_expansionEndCE_[mid] & 0xFFFFFFFFl;\r
193             if (unsignedce <= midce) {\r
194                 limit = mid;\r
195             }\r
196             else {\r
197                 start = mid;\r
198             }\r
199         }\r
200         int result = 1;\r
201         if (m_collator_.m_expansionEndCE_[start] == ce) {\r
202             result = m_collator_.m_expansionEndCEMaxSize_[start];\r
203         }\r
204         else if (limit < m_collator_.m_expansionEndCE_.length &&\r
205                  m_collator_.m_expansionEndCE_[limit] == ce) {\r
206             result = m_collator_.m_expansionEndCEMaxSize_[limit];\r
207         }\r
208         else if ((ce & 0xFFFF) == 0x00C0) {\r
209             result = 2;\r
210         }\r
211         return result;\r
212     }\r
213 \r
214     // public other methods -------------------------------------------------\r
215 \r
216     /**\r
217      * <p> Resets the cursor to the beginning of the string. The next\r
218      * call to next() or previous() will return the first and last\r
219      * collation element in the string, respectively.</p>\r
220      *\r
221      * <p>If the RuleBasedCollator used by this iterator has had its\r
222      * attributes changed, calling reset() will reinitialize the\r
223      * iterator to use the new attributes.</p>\r
224      *\r
225      * @stable ICU 2.8\r
226      */\r
227     public void reset()\r
228     {\r
229         m_source_.setToStart();\r
230         updateInternalState();\r
231     }\r
232 \r
233     /**\r
234      * <p>Get the next collation element in the source string.</p>\r
235      *\r
236      * <p>This iterator iterates over a sequence of collation elements\r
237      * that were built from the string. Because there isn't\r
238      * necessarily a one-to-one mapping from characters to collation\r
239      * elements, this doesn't mean the same thing as "return the\r
240      * collation element [or ordering priority] of the next character\r
241      * in the string".</p>\r
242      *\r
243      * <p>This function returns the collation element that the\r
244      * iterator is currently pointing to, and then updates the\r
245      * internal pointer to point to the next element.  Previous()\r
246      * updates the pointer first, and then returns the element. This\r
247      * means that when you change direction while iterating (i.e.,\r
248      * call next() and then call previous(), or call previous() and\r
249      * then call next()), you'll get back the same element twice.</p>\r
250      *\r
251      * @return the next collation element or NULLORDER if the end of the\r
252      *         iteration has been reached.\r
253      * @stable ICU 2.8\r
254      */\r
255     public int next()\r
256     {\r
257         m_isForwards_ = true;\r
258         if (m_CEBufferSize_ > 0) {\r
259             if (m_CEBufferOffset_ < m_CEBufferSize_) {\r
260                 // if there are expansions left in the buffer, we return it\r
261                 return m_CEBuffer_[m_CEBufferOffset_ ++];\r
262             }\r
263             m_CEBufferSize_ = 0;\r
264             m_CEBufferOffset_ = 0;\r
265         }\r
266  \r
267         int ch_int = nextChar();\r
268         \r
269         if (ch_int == UCharacterIterator.DONE) {\r
270             return NULLORDER;\r
271         }\r
272         char ch = (char)ch_int;\r
273         if (m_collator_.m_isHiragana4_) {\r
274             /* Codepoints \u3099-\u309C are both Hiragana and Katakana. Set the flag\r
275              * based on whether the previous codepoint was Hiragana or Katakana.\r
276              */\r
277             m_isCodePointHiragana_ = (m_isCodePointHiragana_ && (ch >= 0x3099 && ch <= 0x309C)) || \r
278                                      ((ch >= 0x3040 && ch <= 0x309e) && !(ch > 0x3094 && ch < 0x309d));\r
279         }\r
280 \r
281         int result = NULLORDER;\r
282         if (ch <= 0xFF) {\r
283             // For latin-1 characters we never need to fall back to the UCA\r
284             // table because all of the UCA data is replicated in the\r
285             // latinOneMapping array\r
286             result = m_collator_.m_trie_.getLatin1LinearValue(ch);\r
287             if (RuleBasedCollator.isSpecial(result)) {\r
288                 result = nextSpecial(m_collator_, result, ch);\r
289             }\r
290         }\r
291         else {\r
292             result = m_collator_.m_trie_.getLeadValue(ch);\r
293             //System.out.println(Integer.toHexString(result));\r
294             if (RuleBasedCollator.isSpecial(result)) {\r
295                 // surrogate leads are handled as special ces\r
296                 result = nextSpecial(m_collator_, result, ch);\r
297             }\r
298             if (result == CE_NOT_FOUND_ && RuleBasedCollator.UCA_ != null) {\r
299                 // couldn't find a good CE in the tailoring\r
300                 // if we got here, the codepoint MUST be over 0xFF - so we look\r
301                 // directly in the UCA\r
302                 result = RuleBasedCollator.UCA_.m_trie_.getLeadValue(ch);\r
303                 if (RuleBasedCollator.isSpecial(result)) {\r
304                     // UCA also gives us a special CE\r
305                     result = nextSpecial(RuleBasedCollator.UCA_, result, ch);\r
306                 }\r
307             }\r
308         }\r
309         if(result == CE_NOT_FOUND_) { \r
310             // maybe there is no UCA, unlikely in Java, but ported for consistency\r
311             result = nextImplicit(ch); \r
312         }\r
313         return result;\r
314     }\r
315 \r
316     /**\r
317      * <p>Get the previous collation element in the source string.</p>\r
318      *\r
319      * <p>This iterator iterates over a sequence of collation elements\r
320      * that were built from the string. Because there isn't\r
321      * necessarily a one-to-one mapping from characters to collation\r
322      * elements, this doesn't mean the same thing as "return the\r
323      * collation element [or ordering priority] of the previous\r
324      * character in the string".</p>\r
325      *\r
326      * <p>This function updates the iterator's internal pointer to\r
327      * point to the collation element preceding the one it's currently\r
328      * pointing to and then returns that element, while next() returns\r
329      * the current element and then updates the pointer. This means\r
330      * that when you change direction while iterating (i.e., call\r
331      * next() and then call previous(), or call previous() and then\r
332      * call next()), you'll get back the same element twice.</p>\r
333      *\r
334      * @return the previous collation element, or NULLORDER when the start of\r
335      *             the iteration has been reached.\r
336      * @stable ICU 2.8\r
337      */\r
338     public int previous()\r
339     {\r
340         if (m_source_.getIndex() <= 0 && m_isForwards_) {\r
341             // if iterator is new or reset, we can immediate perform  backwards\r
342             // iteration even when the offset is not right.\r
343             m_source_.setToLimit();\r
344             updateInternalState();\r
345         }\r
346         m_isForwards_ = false;\r
347         int result = NULLORDER;\r
348         if (m_CEBufferSize_ > 0) {\r
349             if (m_CEBufferOffset_ > 0) {\r
350                 return m_CEBuffer_[-- m_CEBufferOffset_];\r
351             }\r
352             m_CEBufferSize_ = 0;\r
353             m_CEBufferOffset_ = 0;\r
354         }\r
355         int ch_int = previousChar();\r
356         if (ch_int == UCharacterIterator.DONE) {\r
357             return NULLORDER;\r
358         }\r
359         char ch = (char)ch_int;\r
360         if (m_collator_.m_isHiragana4_) {\r
361             m_isCodePointHiragana_ = (ch >= 0x3040 && ch <= 0x309f);\r
362         }\r
363         if (m_collator_.isContractionEnd(ch) && !isBackwardsStart()) {\r
364             result = previousSpecial(m_collator_, CE_CONTRACTION_, ch);\r
365         }\r
366         else {\r
367             if (ch <= 0xFF) {\r
368                 result = m_collator_.m_trie_.getLatin1LinearValue(ch);\r
369             }\r
370             else {\r
371                 result = m_collator_.m_trie_.getLeadValue(ch);\r
372             }\r
373             if (RuleBasedCollator.isSpecial(result)) {\r
374                 result = previousSpecial(m_collator_, result, ch);\r
375             }\r
376             if (result == CE_NOT_FOUND_) {\r
377                 if (!isBackwardsStart()\r
378                     && m_collator_.isContractionEnd(ch)) {\r
379                     result = CE_CONTRACTION_;\r
380                 }\r
381                 else {\r
382                     if(RuleBasedCollator.UCA_ != null) {\r
383                         result = RuleBasedCollator.UCA_.m_trie_.getLeadValue(ch);\r
384                     }\r
385                 }\r
386 \r
387                 if (RuleBasedCollator.isSpecial(result)) {\r
388                     if(RuleBasedCollator.UCA_ != null) {                    \r
389                         result = previousSpecial(RuleBasedCollator.UCA_, result, ch);\r
390                     }\r
391                 }\r
392             }\r
393         }\r
394         if(result == CE_NOT_FOUND_) {\r
395             result = previousImplicit(ch);\r
396         }\r
397         return result;\r
398     }\r
399 \r
400     /**\r
401      * Return the primary order of the specified collation element,\r
402      * i.e. the first 16 bits.  This value is unsigned.\r
403      * @param ce the collation element\r
404      * @return the element's 16 bits primary order.\r
405      * @stable ICU 2.8\r
406      */\r
407     public final static int primaryOrder(int ce)\r
408     {\r
409         return (ce & RuleBasedCollator.CE_PRIMARY_MASK_)\r
410             >>> RuleBasedCollator.CE_PRIMARY_SHIFT_;\r
411     }\r
412     /**\r
413      * Return the secondary order of the specified collation element,\r
414      * i.e. the 16th to 23th bits, inclusive.  This value is unsigned.\r
415      * @param ce the collation element\r
416      * @return the element's 8 bits secondary order\r
417      * @stable ICU 2.8\r
418      */\r
419     public final static int secondaryOrder(int ce)\r
420     {\r
421         return (ce & RuleBasedCollator.CE_SECONDARY_MASK_)\r
422             >> RuleBasedCollator.CE_SECONDARY_SHIFT_;\r
423     }\r
424 \r
425     /**\r
426      * Return the tertiary order of the specified collation element, i.e. the last\r
427      * 8 bits.  This value is unsigned.\r
428      * @param ce the collation element\r
429      * @return the element's 8 bits tertiary order\r
430      * @stable ICU 2.8\r
431      */\r
432     public final static int tertiaryOrder(int ce)\r
433     {\r
434         return ce & RuleBasedCollator.CE_TERTIARY_MASK_;\r
435     }\r
436 \r
437     /**\r
438      * <p> Sets the iterator to point to the collation element\r
439      * corresponding to the character at the specified offset. The\r
440      * value returned by the next call to next() will be the collation\r
441      * element corresponding to the characters at offset.</p>\r
442      *\r
443      * <p>If offset is in the middle of a contracting character\r
444      * sequence, the iterator is adjusted to the start of the\r
445      * contracting sequence. This means that getOffset() is not\r
446      * guaranteed to return the same value set by this method.</p>\r
447      *\r
448      * <p>If the decomposition mode is on, and offset is in the middle\r
449      * of a decomposible range of source text, the iterator may not\r
450      * return a correct result for the next forwards or backwards\r
451      * iteration.  The user must ensure that the offset is not in the\r
452      * middle of a decomposible range.</p>\r
453      *\r
454      * @param offset the character offset into the original source string to\r
455      *        set. Note that this is not an offset into the corresponding\r
456      *        sequence of collation elements.\r
457      * @stable ICU 2.8\r
458      */\r
459     public void setOffset(int offset)\r
460     {\r
461         m_source_.setIndex(offset);\r
462         int ch_int = m_source_.current();\r
463         char ch = (char)ch_int;\r
464         if (ch_int != UCharacterIterator.DONE && m_collator_.isUnsafe(ch)) {\r
465             // if it is unsafe we need to check if it is part of a contraction\r
466             // or a surrogate character\r
467             if (UTF16.isTrailSurrogate(ch)) {\r
468                 // if it is a surrogate pair we move up one character\r
469                 char prevch = (char)m_source_.previous();\r
470                 if (!UTF16.isLeadSurrogate(prevch)) {\r
471                     m_source_.setIndex(offset); // go back to the same index\r
472                 }\r
473             }\r
474             else {\r
475                 // could be part of a contraction\r
476                 // backup to a safe point and iterate till we pass offset\r
477                 while (m_source_.getIndex() > 0) {\r
478                     if (!m_collator_.isUnsafe(ch)) {\r
479                         break;\r
480                     }\r
481                     ch = (char)m_source_.previous();\r
482                 }\r
483                 updateInternalState();\r
484                 int prevoffset = 0;\r
485                 while (m_source_.getIndex() <= offset) {\r
486                     prevoffset = m_source_.getIndex();\r
487                     next();\r
488                 }\r
489                 m_source_.setIndex(prevoffset);\r
490             }\r
491         }\r
492         updateInternalState();\r
493         // direction code to prevent next and previous from returning a \r
494         // character if we are already at the ends\r
495         offset = m_source_.getIndex();\r
496         if (offset == 0/* m_source_.getBeginIndex() */) {\r
497             // preventing previous() from returning characters from the end of \r
498             // the string again if we are at the beginning\r
499             m_isForwards_ = false; \r
500         }\r
501         else if (offset == m_source_.getLength()) {\r
502             // preventing next() from returning characters from the start of \r
503             // the string again if we are at the end\r
504             m_isForwards_ = true;\r
505         }\r
506     }\r
507 \r
508     /**\r
509      * <p>Set a new source string for iteration, and reset the offset\r
510      * to the beginning of the text.</p>\r
511      *\r
512      * @param source the new source string for iteration.\r
513      * @stable ICU 2.8\r
514      */\r
515     public void setText(String source)\r
516     {\r
517         m_srcUtilIter_.setText(source);\r
518         m_source_ = m_srcUtilIter_;\r
519         updateInternalState();\r
520     }\r
521     \r
522     /**\r
523      * <p>Set a new source string iterator for iteration, and reset the\r
524      * offset to the beginning of the text.\r
525      * </p>\r
526      * <p>The source iterator's integrity will be preserved since a new copy\r
527      * will be created for use.</p>\r
528      * @param source the new source string iterator for iteration.\r
529      * @stable ICU 2.8\r
530      */\r
531     public void setText(UCharacterIterator source)\r
532     {\r
533         m_srcUtilIter_.setText(source.getText());\r
534         m_source_ = m_srcUtilIter_;\r
535         updateInternalState(); \r
536     }\r
537 \r
538     /**\r
539      * <p>Set a new source string iterator for iteration, and reset the\r
540      * offset to the beginning of the text.\r
541      * </p>\r
542      * @param source the new source string iterator for iteration.\r
543      * @stable ICU 2.8\r
544      */\r
545     public void setText(CharacterIterator source)\r
546     {\r
547         m_source_ = new CharacterIteratorWrapper(source);\r
548         m_source_.setToStart();\r
549         updateInternalState();\r
550     }\r
551 \r
552     // public miscellaneous methods -----------------------------------------\r
553 \r
554     /**\r
555      * Tests that argument object is equals to this CollationElementIterator.\r
556      * Iterators are equal if the objects uses the same RuleBasedCollator,\r
557      * the same source text and have the same current position in iteration.\r
558      * @param that object to test if it is equals to this\r
559      *             CollationElementIterator\r
560      * @stable ICU 2.8\r
561      */\r
562     public boolean equals(Object that)\r
563     {\r
564         if (that == this) {\r
565             return true;\r
566         }\r
567         if (that instanceof CollationElementIterator) {\r
568             CollationElementIterator thatceiter\r
569                                               = (CollationElementIterator)that;\r
570             if (!m_collator_.equals(thatceiter.m_collator_)) {\r
571                 return false;\r
572             }\r
573             // checks the text \r
574             return m_source_.getIndex() == thatceiter.m_source_.getIndex()\r
575                    && m_source_.getText().equals(\r
576                                             thatceiter.m_source_.getText());\r
577         }\r
578         return false;\r
579     }\r
580 \r
581     // package private constructors ------------------------------------------\r
582 \r
583     private CollationElementIterator(RuleBasedCollator collator) {\r
584         m_utilStringBuffer_ = new StringBuilder();\r
585         m_collator_ = collator;\r
586         m_CEBuffer_ = new int[CE_BUFFER_INIT_SIZE_];\r
587         m_buffer_ = new StringBuilder();\r
588         m_utilSpecialBackUp_ = new Backup();\r
589         m_nfcImpl_.getFCDTrie();  // ensure the FCD data is initialized\r
590     }\r
591 \r
592     /**\r
593      * <p>CollationElementIterator constructor. This takes a source\r
594      * string and a RuleBasedCollator. The iterator will walk through\r
595      * the source string based on the rules defined by the\r
596      * collator. If the source string is empty, NULLORDER will be\r
597      * returned on the first call to next().</p>\r
598      *\r
599      * @param source the source string.\r
600      * @param collator the RuleBasedCollator\r
601      * @stable ICU 2.8\r
602      */\r
603     CollationElementIterator(String source, RuleBasedCollator collator)\r
604     {\r
605         this(collator);\r
606         m_source_ = m_srcUtilIter_ = new StringUCharacterIterator(source);\r
607         updateInternalState();\r
608     }\r
609 \r
610     /**\r
611      * <p>CollationElementIterator constructor. This takes a source\r
612      * character iterator and a RuleBasedCollator. The iterator will\r
613      * walk through the source string based on the rules defined by\r
614      * the collator. If the source string is empty, NULLORDER will be\r
615      * returned on the first call to next().</p>\r
616      *\r
617      * @param source the source string iterator.\r
618      * @param collator the RuleBasedCollator\r
619      * @stable ICU 2.8\r
620      */\r
621     CollationElementIterator(CharacterIterator source,\r
622                              RuleBasedCollator collator)\r
623     {\r
624         this(collator);\r
625         m_srcUtilIter_ = new StringUCharacterIterator();\r
626         m_source_ = new CharacterIteratorWrapper(source);\r
627         updateInternalState();\r
628     }\r
629     \r
630     /**\r
631      * <p>CollationElementIterator constructor. This takes a source\r
632      * character iterator and a RuleBasedCollator. The iterator will\r
633      * walk through the source string based on the rules defined by\r
634      * the collator. If the source string is empty, NULLORDER will be\r
635      * returned on the first call to next().</p>\r
636      *\r
637      * @param source the source string iterator.\r
638      * @param collator the RuleBasedCollator\r
639      * @stable ICU 2.8\r
640      */\r
641     CollationElementIterator(UCharacterIterator source,\r
642                              RuleBasedCollator collator)\r
643     {\r
644         this(collator);\r
645         m_srcUtilIter_ = new StringUCharacterIterator();\r
646         m_srcUtilIter_.setText(source.getText());\r
647         m_source_ = m_srcUtilIter_;\r
648         updateInternalState();\r
649     }\r
650 \r
651     // package private data members -----------------------------------------\r
652 \r
653     /**\r
654      * true if current codepoint was Hiragana\r
655      */\r
656     boolean m_isCodePointHiragana_;\r
657     /**\r
658      * Position in the original string that starts with a non-FCD sequence\r
659      */\r
660     int m_FCDStart_;\r
661     /**\r
662      * This is the CE from CEs buffer that should be returned.\r
663      * Initial value is 0.\r
664      * Forwards iteration will end with m_CEBufferOffset_ == m_CEBufferSize_,\r
665      * backwards will end with m_CEBufferOffset_ == 0.\r
666      * The next/previous after we reach the end/beginning of the m_CEBuffer_\r
667      * will cause this value to be reset to 0.\r
668      */\r
669     int m_CEBufferOffset_;\r
670 \r
671     /**\r
672      * This is the position to which we have stored processed CEs.\r
673      * Initial value is 0.\r
674      * The next/previous after we reach the end/beginning of the m_CEBuffer_\r
675      * will cause this value to be reset to 0.\r
676      */\r
677     int m_CEBufferSize_;\r
678     static final int CE_NOT_FOUND_ = 0xF0000000;\r
679     static final int CE_EXPANSION_TAG_ = 1;\r
680     static final int CE_CONTRACTION_TAG_ = 2;\r
681     /** \r
682      * Collate Digits As Numbers (CODAN) implementation\r
683      */\r
684     static final int CE_DIGIT_TAG_ = 13;\r
685 \r
686     // package private methods ----------------------------------------------\r
687 \r
688     /**\r
689      * Sets the collator used.\r
690      * Internal use, all data members will be reset to the default values\r
691      * @param collator to set\r
692      */\r
693     void setCollator(RuleBasedCollator collator)\r
694     {\r
695         m_collator_ = collator;\r
696         updateInternalState();\r
697     }\r
698 \r
699     /**\r
700      * <p>Sets the iterator to point to the collation element corresponding to\r
701      * the specified character (the parameter is a CHARACTER offset in the\r
702      * original string, not an offset into its corresponding sequence of\r
703      * collation elements). The value returned by the next call to next()\r
704      * will be the collation element corresponding to the specified position\r
705      * in the text. Unlike the public method setOffset(int), this method does\r
706      * not try to readjust the offset to the start of a contracting sequence.\r
707      * getOffset() is guaranteed to return the same value as was passed to a\r
708      * preceding call to setOffset().</p>\r
709      * @param offset new character offset into the original text to set.\r
710      */\r
711     void setExactOffset(int offset)\r
712     {\r
713         m_source_.setIndex(offset);\r
714         updateInternalState();\r
715     }\r
716 \r
717     /**\r
718      * Checks if iterator is in the buffer zone\r
719      * @return true if iterator is in buffer zone, false otherwise\r
720      */\r
721     boolean isInBuffer()\r
722     {\r
723         return m_bufferOffset_ > 0;\r
724     }\r
725 \r
726    \r
727     /**\r
728      * <p>Sets the iterator to point to the collation element corresponding to\r
729      * the specified character (the parameter is a CHARACTER offset in the\r
730      * original string, not an offset into its corresponding sequence of\r
731      * collation elements). The value returned by the next call to next()\r
732      * will be the collation element corresponding to the specified position\r
733      * in the text. Unlike the public method setOffset(int), this method does\r
734      * not try to readjust the offset to the start of a contracting sequence.\r
735      * getOffset() is guaranteed to return the same value as was passed to a\r
736      * preceding call to setOffset().</p>\r
737      * </p>\r
738      * @param source the new source string iterator for iteration.\r
739      * @param offset to the source\r
740      */\r
741     void setText(UCharacterIterator source, int offset)\r
742     {\r
743         m_srcUtilIter_.setText(source.getText());\r
744         m_source_ = m_srcUtilIter_;\r
745         m_source_.setIndex(offset);\r
746         updateInternalState();\r
747     }\r
748 \r
749     // private inner class --------------------------------------------------\r
750 \r
751     /**\r
752      * Backup data class\r
753      */\r
754     private static final class Backup\r
755     {\r
756         // protected data members -------------------------------------------\r
757 \r
758         /**\r
759          * Backup non FCD sequence limit\r
760          */\r
761         protected int m_FCDLimit_;\r
762         /**\r
763          * Backup non FCD sequence start\r
764          */\r
765         protected int m_FCDStart_;\r
766         /**\r
767          * Backup if previous Codepoint is Hiragana quatenary\r
768          */\r
769         protected boolean m_isCodePointHiragana_;\r
770         /**\r
771          * Backup buffer position\r
772          */\r
773         protected int m_bufferOffset_;\r
774         /**\r
775          * Backup source iterator offset\r
776          */\r
777         protected int m_offset_;\r
778         /**\r
779          * Backup buffer contents\r
780          */\r
781         protected StringBuffer m_buffer_;\r
782 \r
783         // protected constructor --------------------------------------------\r
784 \r
785         /**\r
786          * Empty constructor\r
787          */\r
788         protected Backup()\r
789         {\r
790             m_buffer_ = new StringBuffer();\r
791         }\r
792     }\r
793     // end inner class ------------------------------------------------------\r
794 \r
795     /**\r
796      * Direction of travel\r
797      */\r
798     private boolean m_isForwards_;\r
799     /**\r
800      * Source string iterator\r
801      */\r
802     private UCharacterIterator m_source_;\r
803     /**\r
804      * This is position to the m_buffer_, -1 if iterator is not in m_buffer_\r
805      */\r
806     private int m_bufferOffset_;\r
807     /**\r
808      * Buffer for temporary storage of normalized characters, discontiguous\r
809      * characters and Thai characters\r
810      */\r
811     private StringBuilder m_buffer_;\r
812     /**\r
813      * Position in the original string to continue forward FCD check from.\r
814      */\r
815     private int m_FCDLimit_;\r
816     /**\r
817      * The collator this iterator is based on\r
818      */\r
819     private RuleBasedCollator m_collator_;\r
820     /**\r
821      * true if Hiragana quatenary is on\r
822      */\r
823     //private boolean m_isHiragana4_;\r
824     /**\r
825      * CE buffer\r
826      */\r
827     private int m_CEBuffer_[];\r
828     /**\r
829      * In reality we should not have to deal with expansion sequences longer\r
830      * then 16. However this value can be change if a bigger buffer is needed.\r
831      * Note, if the size is change to too small a number, BIG trouble.\r
832      * Reasonable small value is around 10, if there's no Arabic or other\r
833      * funky collations that have long expansion sequence. This is the longest\r
834      * expansion sequence this can handle without bombing out.\r
835      */\r
836     private static final int CE_BUFFER_INIT_SIZE_ = 512;\r
837     /**\r
838      * Backup storage for special processing inner cases\r
839      */\r
840     private Backup m_utilSpecialBackUp_;\r
841     /**\r
842      * Backup storage in special processing entry state\r
843      */\r
844     private Backup m_utilSpecialEntryBackUp_;\r
845     /**\r
846      * Backup storage in special processing discontiguous state\r
847      */\r
848     private Backup m_utilSpecialDiscontiguousBackUp_;\r
849     /**\r
850      * Utility\r
851      */\r
852     private StringUCharacterIterator m_srcUtilIter_;\r
853     private StringBuilder m_utilStringBuffer_;\r
854     private StringBuilder m_utilSkippedBuffer_;\r
855     private CollationElementIterator m_utilColEIter_;\r
856     private static final Normalizer2Impl m_nfcImpl_ = Norm2AllModes.getNFCInstance().impl;\r
857     private StringBuilder m_unnormalized_;\r
858     private Normalizer2Impl.ReorderingBuffer m_n2Buffer_;\r
859     /**\r
860      * The first non-zero combining class character\r
861      */\r
862     private static final int FULL_ZERO_COMBINING_CLASS_FAST_LIMIT_ = 0xC0;\r
863     /**\r
864      * One character before the first character with leading non-zero combining\r
865      * class\r
866      */\r
867     private static final int LEAD_ZERO_COMBINING_CLASS_FAST_LIMIT_ = 0x300;\r
868     /**\r
869      * Mask for the last byte\r
870      */\r
871     private static final int LAST_BYTE_MASK_ = 0xFF;\r
872     /**\r
873      * Shift value for the second last byte\r
874      */\r
875     private static final int SECOND_LAST_BYTE_SHIFT_ = 8;\r
876 \r
877     // special ce values and tags -------------------------------------------\r
878     \r
879 //    private static final int CE_EXPANSION_ = 0xF1000000;\r
880     private static final int CE_CONTRACTION_ = 0xF2000000;\r
881     /**\r
882      * Indicates the last ce has been consumed. Compare with NULLORDER.\r
883      * NULLORDER is returned if error occurs.\r
884      */\r
885 /*    private static final int CE_NO_MORE_CES_ = 0x00010101;\r
886     private static final int CE_NO_MORE_CES_PRIMARY_ = 0x00010000;\r
887     private static final int CE_NO_MORE_CES_SECONDARY_ = 0x00000100;\r
888     private static final int CE_NO_MORE_CES_TERTIARY_ = 0x00000001;\r
889 */\r
890     private static final int CE_NOT_FOUND_TAG_ = 0;\r
891     /**\r
892      * Charset processing, not yet implemented\r
893      */\r
894     private static final int CE_CHARSET_TAG_ = 4;\r
895     /**\r
896      * AC00-D7AF\r
897      */\r
898     private static final int CE_HANGUL_SYLLABLE_TAG_ = 6;\r
899     /**\r
900      * D800-DBFF\r
901      */\r
902     private static final int CE_LEAD_SURROGATE_TAG_ = 7;\r
903     /**\r
904      * DC00-DFFF\r
905      */\r
906     private static final int CE_TRAIL_SURROGATE_TAG_ = 8;\r
907     /**\r
908      * 0x3400-0x4DB5, 0x4E00-0x9FA5, 0xF900-0xFA2D\r
909      */\r
910     private static final int CE_CJK_IMPLICIT_TAG_ = 9;\r
911     private static final int CE_IMPLICIT_TAG_ = 10;\r
912     static final int CE_SPEC_PROC_TAG_ = 11;\r
913     /**\r
914      * This is a 3 byte primary with starting secondaries and tertiaries.\r
915      * It fits in a single 32 bit CE and is used instead of expansion to save\r
916      * space without affecting the performance (hopefully).\r
917      */\r
918     private static final int CE_LONG_PRIMARY_TAG_ = 12;\r
919                         \r
920 //    private static final int CE_CE_TAGS_COUNT = 14;\r
921     private static final int CE_BYTE_COMMON_ = 0x05;\r
922 \r
923     // end special ce values and tags ---------------------------------------\r
924 \r
925     private static final int HANGUL_SBASE_ = 0xAC00;\r
926     private static final int HANGUL_LBASE_ = 0x1100;\r
927     private static final int HANGUL_VBASE_ = 0x1161;\r
928     private static final int HANGUL_TBASE_ = 0x11A7;\r
929     private static final int HANGUL_VCOUNT_ = 21;\r
930     private static final int HANGUL_TCOUNT_ = 28;\r
931 \r
932     // CJK stuff ------------------------------------------------------------\r
933 \r
934 /*    private static final int CJK_BASE_ = 0x4E00;\r
935     private static final int CJK_LIMIT_ = 0x9FFF+1;\r
936     private static final int CJK_COMPAT_USED_BASE_ = 0xFA0E;\r
937     private static final int CJK_COMPAT_USED_LIMIT_ = 0xFA2F + 1;\r
938     private static final int CJK_A_BASE_ = 0x3400;\r
939     private static final int CJK_A_LIMIT_ = 0x4DBF + 1;\r
940     private static final int CJK_B_BASE_ = 0x20000;\r
941     private static final int CJK_B_LIMIT_ = 0x2A6DF + 1;\r
942     private static final int NON_CJK_OFFSET_ = 0x110000;\r
943 */\r
944     private static final boolean DEBUG  =  ICUDebug.enabled("collator");\r
945     \r
946     // private methods ------------------------------------------------------\r
947 \r
948     /**\r
949      * Reset the iterator internally\r
950      */\r
951     private void updateInternalState()\r
952     {\r
953         m_isCodePointHiragana_ = false;\r
954         m_buffer_.setLength(0);\r
955         m_bufferOffset_ = -1;\r
956         m_CEBufferOffset_ = 0;\r
957         m_CEBufferSize_ = 0;\r
958         m_FCDLimit_ = -1;\r
959         m_FCDStart_ = m_source_.getLength();\r
960         //m_isHiragana4_ = m_collator_.m_isHiragana4_;\r
961         m_isForwards_ = true;\r
962     }\r
963 \r
964     /**\r
965      * Backup the current internal state\r
966      * @param backup object to store the data\r
967      */\r
968     private void backupInternalState(Backup backup)\r
969     {\r
970         backup.m_offset_ = m_source_.getIndex();\r
971         backup.m_FCDLimit_ = m_FCDLimit_;\r
972         backup.m_FCDStart_ = m_FCDStart_;\r
973         backup.m_isCodePointHiragana_ = m_isCodePointHiragana_;\r
974         backup.m_bufferOffset_ = m_bufferOffset_;\r
975         backup.m_buffer_.setLength(0);\r
976         if (m_bufferOffset_ >= 0) {\r
977             backup.m_buffer_.append(m_buffer_);\r
978         }\r
979     }\r
980 \r
981     /**\r
982      * Update the iterator internally with backed-up state\r
983      * @param backup object that stored the data\r
984      */\r
985     private void updateInternalState(Backup backup)\r
986     {\r
987         m_source_.setIndex(backup.m_offset_);\r
988         m_isCodePointHiragana_ = backup.m_isCodePointHiragana_;\r
989         m_bufferOffset_ = backup.m_bufferOffset_;\r
990         m_FCDLimit_ = backup.m_FCDLimit_;\r
991         m_FCDStart_ = backup.m_FCDStart_;\r
992         m_buffer_.setLength(0);\r
993         if (m_bufferOffset_ >= 0) {\r
994             m_buffer_.append(backup.m_buffer_);\r
995         }\r
996     }\r
997 \r
998     /**\r
999      * A fast combining class retrieval system.\r
1000      * @param ch UTF16 character\r
1001      * @return combining class of ch\r
1002      */\r
1003     private int getCombiningClass(int ch)\r
1004     {\r
1005         if (ch >= LEAD_ZERO_COMBINING_CLASS_FAST_LIMIT_ &&\r
1006             m_collator_.isUnsafe((char)ch) || ch > 0xFFFF\r
1007         ) {\r
1008             return m_nfcImpl_.getCC(m_nfcImpl_.getNorm16(ch));\r
1009         }\r
1010         return 0;\r
1011     }\r
1012 \r
1013     /**\r
1014      * <p>Incremental normalization, this is an essential optimization.\r
1015      * Assuming FCD checks has been done, normalize the non-FCD characters into\r
1016      * the buffer.\r
1017      * Source offsets points to the current processing character.\r
1018      * </p>\r
1019      */\r
1020     private void normalize()\r
1021     {\r
1022         if (m_unnormalized_ == null) {\r
1023             m_unnormalized_ = new StringBuilder();\r
1024             m_n2Buffer_ = new Normalizer2Impl.ReorderingBuffer(m_nfcImpl_, m_buffer_, 10);\r
1025         } else {\r
1026             m_unnormalized_.setLength(0);\r
1027             m_n2Buffer_.remove();\r
1028         }\r
1029         int size = m_FCDLimit_ - m_FCDStart_;\r
1030         m_source_.setIndex(m_FCDStart_);\r
1031         for (int i = 0; i < size; i ++) {\r
1032             m_unnormalized_.append((char)m_source_.next());\r
1033         }\r
1034         m_nfcImpl_.decomposeShort(m_unnormalized_, 0, size, m_n2Buffer_);\r
1035     }\r
1036 \r
1037     /**\r
1038      * <p>Incremental FCD check and normalization. Gets the next base character\r
1039      * position and determines if the in-between characters needs normalization.\r
1040      * </p>\r
1041      * <p>When entering, the state is known to be this:\r
1042      * <ul>\r
1043      * <li>We are working on source string, not the buffer.\r
1044      * <li>The leading combining class from the current character is 0 or the\r
1045      *     trailing combining class of the previous char was zero.\r
1046      * </ul>\r
1047      * Incoming source offsets points to the current processing character.\r
1048      * Return source offsets points to the current processing character.\r
1049      * </p>\r
1050      * @param ch current character (lead unit)\r
1051      * @param offset offset of ch +1\r
1052      * @return true if FCDCheck passes, false otherwise\r
1053      */\r
1054     private boolean FCDCheck(int ch, int offset)\r
1055     {\r
1056         boolean result = true;\r
1057 \r
1058         // Get the trailing combining class of the current character.\r
1059         // If it's zero, we are OK.\r
1060         m_FCDStart_ = offset - 1;\r
1061         m_source_.setIndex(offset);\r
1062         // trie access\r
1063         int fcd = m_nfcImpl_.getFCD16FromSingleLead((char)ch);\r
1064         if (fcd != 0 && Character.isHighSurrogate((char)ch)) {\r
1065             int c2 = m_source_.next(); \r
1066             if (c2 < 0) {\r
1067                 fcd = 0;  // end of input\r
1068             } else if (Character.isLowSurrogate((char)c2)) {\r
1069                 fcd = m_nfcImpl_.getFCD16(Character.toCodePoint((char)ch, (char)c2));\r
1070             } else {\r
1071                 m_source_.moveIndex(-1);\r
1072                 fcd = 0;\r
1073             }\r
1074         }\r
1075 \r
1076         int prevTrailCC = fcd & LAST_BYTE_MASK_;\r
1077 \r
1078         if (prevTrailCC == 0) {\r
1079             offset = m_source_.getIndex();\r
1080         } else {\r
1081             // The current char has a non-zero trailing CC. Scan forward until\r
1082             // we find a char with a leading cc of zero.\r
1083             while (true) {\r
1084                 ch = m_source_.nextCodePoint();\r
1085                 if (ch < 0) {\r
1086                     offset = m_source_.getIndex();\r
1087                     break;\r
1088                 }\r
1089                 // trie access\r
1090                 fcd = m_nfcImpl_.getFCD16(ch);\r
1091                 int leadCC = fcd >> SECOND_LAST_BYTE_SHIFT_;\r
1092                 if (leadCC == 0) {\r
1093                     // this is a base character, we stop the FCD checks\r
1094                     offset = m_source_.getIndex() - Character.charCount(ch);\r
1095                     break;\r
1096                 }\r
1097 \r
1098                 if (leadCC < prevTrailCC) {\r
1099                     result = false;\r
1100                 }\r
1101 \r
1102                 prevTrailCC = fcd & LAST_BYTE_MASK_;\r
1103             }\r
1104         }\r
1105         m_FCDLimit_ = offset;\r
1106         m_source_.setIndex(m_FCDStart_ + 1);\r
1107         return result;\r
1108     }\r
1109 \r
1110     /**\r
1111      * <p>Method tries to fetch the next character that is in fcd form.</p>\r
1112      * <p>Normalization is done if required.</p>\r
1113      * <p>Offsets are returned at the next character.</p>\r
1114      * @return next fcd character\r
1115      */\r
1116     private int nextChar()\r
1117     {\r
1118         int result;\r
1119 \r
1120         // loop handles the next character whether it is in the buffer or not.\r
1121         if (m_bufferOffset_ < 0) {\r
1122             // we're working on the source and not normalizing. fast path.\r
1123             // note Thai pre-vowel reordering uses buffer too\r
1124             result = m_source_.next();\r
1125         }\r
1126         else {\r
1127             // we are in the buffer, buffer offset will never be 0 here\r
1128             if (m_bufferOffset_ >= m_buffer_.length()) {\r
1129                 // Null marked end of buffer, revert to the source string and\r
1130                 // loop back to top to try again to get a character.\r
1131                 m_source_.setIndex(m_FCDLimit_);\r
1132                 m_bufferOffset_ = -1;\r
1133                 m_buffer_.setLength(0);\r
1134                 return nextChar();\r
1135             }\r
1136             return m_buffer_.charAt(m_bufferOffset_ ++);\r
1137         }\r
1138         int startoffset = m_source_.getIndex();\r
1139         if (result < FULL_ZERO_COMBINING_CLASS_FAST_LIMIT_\r
1140             // Fast fcd safe path. trail combining class == 0.\r
1141             || m_collator_.getDecomposition() == Collator.NO_DECOMPOSITION\r
1142             || m_bufferOffset_ >= 0 || m_FCDLimit_ >= startoffset) {\r
1143             // skip the fcd checks\r
1144             return result;\r
1145         }\r
1146 \r
1147         if (result < LEAD_ZERO_COMBINING_CLASS_FAST_LIMIT_) {\r
1148             // We need to peek at the next character in order to tell if we are\r
1149             // FCD\r
1150             int next = m_source_.current();\r
1151             if (next == UCharacterIterator.DONE\r
1152                 || next < LEAD_ZERO_COMBINING_CLASS_FAST_LIMIT_) {\r
1153                 return result; // end of source string and if next character\r
1154                 // starts with a base character is always fcd.\r
1155             }\r
1156         }\r
1157 \r
1158         // Need a more complete FCD check and possible normalization.\r
1159         if (!FCDCheck(result, startoffset)) {\r
1160             normalize();\r
1161             result = m_buffer_.charAt(0);\r
1162             m_bufferOffset_ = 1;\r
1163         }\r
1164         return result;\r
1165     }\r
1166 \r
1167     /**\r
1168      * <p>Incremental normalization, this is an essential optimization.\r
1169      * Assuming FCD checks has been done, normalize the non-FCD characters into\r
1170      * the buffer.\r
1171      * Source offsets points to the current processing character.</p>\r
1172      */\r
1173     private void normalizeBackwards()\r
1174     {\r
1175         normalize();\r
1176         m_bufferOffset_ = m_buffer_.length();\r
1177     }\r
1178 \r
1179     /**\r
1180      * <p>Incremental backwards FCD check and normalization. Gets the previous\r
1181      * base character position and determines if the in-between characters\r
1182      * needs normalization.\r
1183      * </p>\r
1184      * <p>When entering, the state is known to be this:\r
1185      * <ul>\r
1186      * <li>We are working on source string, not the buffer.\r
1187      * <li>The trailing combining class from the current character is 0 or the\r
1188      *     leading combining class of the next char was zero.\r
1189      * </ul>\r
1190      * Input source offsets points to the previous character.\r
1191      * Return source offsets points to the current processing character.\r
1192      * </p>\r
1193      * @param ch current character\r
1194      * @param offset current character offset\r
1195      * @return true if FCDCheck passes, false otherwise\r
1196      */\r
1197     private boolean FCDCheckBackwards(int ch, int offset)\r
1198     {\r
1199         int fcd;\r
1200         m_FCDLimit_ = offset + 1;\r
1201         m_source_.setIndex(offset);\r
1202         if (!UTF16.isSurrogate((char)ch)) {\r
1203             fcd = m_nfcImpl_.getFCD16FromSingleLead((char)ch);\r
1204         } else {\r
1205             fcd = 0;\r
1206             if (!Normalizer2Impl.UTF16Plus.isSurrogateLead(ch)) {\r
1207                 int c2 = m_source_.previous();\r
1208                 if (c2 < 0) {\r
1209                     // start of input\r
1210                 } else if (Character.isHighSurrogate((char)c2)) {\r
1211                     ch = Character.toCodePoint((char)c2, (char)ch);\r
1212                     fcd = m_nfcImpl_.getFCD16(ch);\r
1213                     --offset;\r
1214                 } else {\r
1215                     m_source_.moveIndex(1);\r
1216                 }\r
1217             }\r
1218         }\r
1219 \r
1220         // Scan backward until we find a char with a leading cc of zero.\r
1221         boolean result = true;\r
1222         if (fcd != 0) {\r
1223             int leadCC;\r
1224             for (;;) {\r
1225                 leadCC = fcd >> SECOND_LAST_BYTE_SHIFT_;\r
1226                 if (leadCC == 0 || (ch = m_source_.previousCodePoint()) < 0) {\r
1227                     offset = m_source_.getIndex();\r
1228                     break;\r
1229                 }\r
1230                 fcd = m_nfcImpl_.getFCD16(ch);\r
1231                 int prevTrailCC = fcd & LAST_BYTE_MASK_;\r
1232                 if (leadCC < prevTrailCC) {\r
1233                     result = false;\r
1234                 } else if (fcd == 0) {\r
1235                     offset = m_source_.getIndex() + Character.charCount(ch);\r
1236                     break;\r
1237                 }\r
1238             }\r
1239         }\r
1240 \r
1241         // storing character with 0 lead fcd or the 1st accent with a base\r
1242         // character before it\r
1243         m_FCDStart_ = offset;\r
1244         m_source_.setIndex(m_FCDLimit_);\r
1245         return result;\r
1246     }\r
1247 \r
1248     /**\r
1249      * <p>Method tries to fetch the previous character that is in fcd form.</p>\r
1250      * <p>Normalization is done if required.</p>\r
1251      * <p>Offsets are returned at the current character.</p>\r
1252      * @return previous fcd character\r
1253      */\r
1254     private int previousChar()\r
1255     {\r
1256         if (m_bufferOffset_ >= 0) {\r
1257             m_bufferOffset_ --;\r
1258             if (m_bufferOffset_ >= 0) {\r
1259                 return m_buffer_.charAt(m_bufferOffset_);\r
1260             }\r
1261             else {\r
1262                 // At the start of buffer, route back to string.\r
1263                 m_buffer_.setLength(0);\r
1264                 if (m_FCDStart_ == 0) {\r
1265                     m_FCDStart_ = -1;\r
1266                     m_source_.setIndex(0);\r
1267                     return UCharacterIterator.DONE;\r
1268                 }\r
1269                 else {\r
1270                     m_FCDLimit_ = m_FCDStart_;\r
1271                     m_source_.setIndex(m_FCDStart_);\r
1272                     return previousChar();\r
1273                 }\r
1274             }\r
1275         }\r
1276         int result = m_source_.previous();\r
1277         int startoffset = m_source_.getIndex();\r
1278         if (result < LEAD_ZERO_COMBINING_CLASS_FAST_LIMIT_\r
1279             || m_collator_.getDecomposition() == Collator.NO_DECOMPOSITION\r
1280             || m_FCDStart_ <= startoffset || m_source_.getIndex() == 0) {\r
1281             return result;\r
1282         }\r
1283         int ch = m_source_.previous();\r
1284         if (ch < FULL_ZERO_COMBINING_CLASS_FAST_LIMIT_) {\r
1285             // if previous character is FCD\r
1286             m_source_.next();\r
1287             return result;\r
1288         }\r
1289         // Need a more complete FCD check and possible normalization.\r
1290         if (!FCDCheckBackwards(result, startoffset)) {\r
1291             normalizeBackwards();\r
1292             m_bufferOffset_ --;\r
1293             result = m_buffer_.charAt(m_bufferOffset_);\r
1294         }\r
1295         else {\r
1296             // fcd checks always reset m_source_ to the limit of the FCD\r
1297             m_source_.setIndex(startoffset);\r
1298         }\r
1299         return result;\r
1300     }\r
1301 \r
1302     /**\r
1303      * Determines if it is at the start of source iteration\r
1304      * @return true if iterator at the start, false otherwise\r
1305      */\r
1306     private final boolean isBackwardsStart()\r
1307     {\r
1308         return (m_bufferOffset_ < 0 && m_source_.getIndex() == 0)\r
1309             || (m_bufferOffset_ == 0 && m_FCDStart_ <= 0);\r
1310     }\r
1311 \r
1312     /**\r
1313      * Checks if iterator is at the end of its source string.\r
1314      * @return true if it is at the end, false otherwise\r
1315      */\r
1316     private final boolean isEnd()\r
1317     {\r
1318         if (m_bufferOffset_ >= 0) {\r
1319             if (m_bufferOffset_ != m_buffer_.length()) {\r
1320                 return false;\r
1321             }\r
1322             else {\r
1323                 // at end of buffer. check if fcd is at the end\r
1324                 return m_FCDLimit_ == m_source_.getLength();\r
1325             }\r
1326         }\r
1327         return m_source_.getLength() == m_source_.getIndex();\r
1328     }\r
1329 \r
1330     /**\r
1331      * <p>Special CE management for surrogates</p>\r
1332      * <p>Lead surrogate is encountered. CE to be retrieved by using the\r
1333      * following code unit. If next character is a trail surrogate, both\r
1334      * characters will be combined to retrieve the CE, otherwise completely\r
1335      * ignorable (UCA specification) is returned.</p>\r
1336      * @param collator collator to use\r
1337      * @param ce current CE\r
1338      * @param trail character\r
1339      * @return next CE for the surrogate characters\r
1340      */\r
1341     private final int nextSurrogate(RuleBasedCollator collator, int ce,\r
1342                                     char trail)\r
1343     {\r
1344         if (!UTF16.isTrailSurrogate(trail)) {\r
1345             updateInternalState(m_utilSpecialBackUp_);\r
1346             return IGNORABLE;\r
1347         }\r
1348         // TODO: CE contain the data from the previous CE + the mask.\r
1349         // It should at least be unmasked\r
1350         int result = collator.m_trie_.getTrailValue(ce, trail);\r
1351         if (result == CE_NOT_FOUND_) {\r
1352             updateInternalState(m_utilSpecialBackUp_);\r
1353         }\r
1354         return result;\r
1355     }\r
1356 \r
1357     /**\r
1358      * Gets the CE expansion offset\r
1359      * @param collator current collator\r
1360      * @param ce ce to test\r
1361      * @return expansion offset\r
1362      */\r
1363     private int getExpansionOffset(RuleBasedCollator collator, int ce)\r
1364     {\r
1365         return ((ce & 0xFFFFF0) >> 4) - collator.m_expansionOffset_;\r
1366     }\r
1367 \r
1368 \r
1369     /**\r
1370      * Gets the contraction ce offset\r
1371      * @param collator current collator\r
1372      * @param ce current ce\r
1373      * @return contraction offset\r
1374      */\r
1375     private int getContractionOffset(RuleBasedCollator collator, int ce)\r
1376     {\r
1377         return (ce & 0xFFFFFF) - collator.m_contractionOffset_;\r
1378     }\r
1379 \r
1380     /**\r
1381      * Checks if CE is a special tag CE\r
1382      * @param ce to check\r
1383      * @return true if CE is a special tag CE, false otherwise\r
1384      */\r
1385     private boolean isSpecialPrefixTag(int ce)\r
1386     {\r
1387         return RuleBasedCollator.isSpecial(ce) &&\r
1388             RuleBasedCollator.getTag(ce) == CE_SPEC_PROC_TAG_;\r
1389     }\r
1390 \r
1391     /**\r
1392      * <p>Special processing getting a CE that is preceded by a certain\r
1393      * prefix.</p>\r
1394      * <p>Used for optimizing Japanese length and iteration marks. When a\r
1395      * special processing tag is encountered, iterate backwards to see if\r
1396      * there's a match.</p>\r
1397      * <p>Contraction tables are used, prefix data is stored backwards in the\r
1398      * table.</p>\r
1399      * @param collator collator to use\r
1400      * @param ce current ce\r
1401      * @param entrybackup entry backup iterator status\r
1402      * @return next collation element\r
1403      */\r
1404     private int nextSpecialPrefix(RuleBasedCollator collator, int ce,\r
1405                                   Backup entrybackup)\r
1406     {\r
1407         backupInternalState(m_utilSpecialBackUp_);\r
1408         updateInternalState(entrybackup);\r
1409         previousChar();\r
1410         // We want to look at the character where we entered\r
1411 \r
1412         while (true) {\r
1413             // This loop will run once per source string character, for as\r
1414             // long as we are matching a potential contraction sequence\r
1415             // First we position ourselves at the begining of contraction\r
1416             // sequence\r
1417             int entryoffset = getContractionOffset(collator, ce);\r
1418             int offset = entryoffset;\r
1419             if (isBackwardsStart()) {\r
1420                 ce = collator.m_contractionCE_[offset];\r
1421                 break;\r
1422             }\r
1423             char previous = (char)previousChar();\r
1424             while (previous > collator.m_contractionIndex_[offset]) {\r
1425                 // contraction characters are ordered, skip smaller characters\r
1426                 offset ++;\r
1427             }\r
1428 \r
1429             if (previous == collator.m_contractionIndex_[offset]) {\r
1430                 // Found the source string char in the table.\r
1431                 // Pick up the corresponding CE from the table.\r
1432                 ce = collator.m_contractionCE_[offset];\r
1433             }\r
1434             else {\r
1435                 // Source string char was not in the table, prefix not found\r
1436                 ce = collator.m_contractionCE_[entryoffset];\r
1437             }\r
1438 \r
1439             if (!isSpecialPrefixTag(ce)) {\r
1440                 // The source string char was in the contraction table, and\r
1441                 // the corresponding CE is not a prefix CE. We found the\r
1442                 // prefix, break out of loop, this CE will end up being\r
1443                 // returned. This is the normal way out of prefix handling\r
1444                 // when the source actually contained the prefix.\r
1445                 break;\r
1446             }\r
1447         }\r
1448         if (ce != CE_NOT_FOUND_) {\r
1449             // we found something and we can merilly continue\r
1450             updateInternalState(m_utilSpecialBackUp_);\r
1451         }\r
1452         else { // prefix search was a failure, we have to backup all the way to\r
1453             // the start\r
1454             updateInternalState(entrybackup);\r
1455         }\r
1456         return ce;\r
1457     }\r
1458 \r
1459     /**\r
1460      * Checks if the ce is a contraction tag\r
1461      * @param ce ce to check\r
1462      * @return true if ce is a contraction tag, false otherwise\r
1463      */\r
1464     private boolean isContractionTag(int ce)\r
1465     {\r
1466         return RuleBasedCollator.isSpecial(ce) &&\r
1467             RuleBasedCollator.getTag(ce) == CE_CONTRACTION_TAG_;\r
1468     }\r
1469 \r
1470     /**\r
1471      * Method to copy skipped characters into the buffer and sets the fcd\r
1472      * position. To ensure that the skipped characters are considered later,\r
1473      * we need to place it in the appropriate position in the buffer and\r
1474      * reassign the source index. simple case if index reside in string,\r
1475      * simply copy to buffer and fcdposition = pos, pos = start of buffer.\r
1476      * if pos in normalization buffer, we'll insert the copy infront of pos\r
1477      * and point pos to the start of the buffer. why am i doing these copies?\r
1478      * well, so that the whole chunk of codes in the getNextCE,\r
1479      * ucol_prv_getSpecialCE does not require any changes, which will be\r
1480      * really painful.\r
1481      * @param skipped character buffer\r
1482      */\r
1483     private void setDiscontiguous(StringBuilder skipped)\r
1484     {\r
1485         if (m_bufferOffset_ >= 0) {\r
1486             m_buffer_.replace(0, m_bufferOffset_, skipped.toString());\r
1487         }\r
1488         else {\r
1489             m_FCDLimit_ = m_source_.getIndex();\r
1490             m_buffer_.setLength(0);\r
1491             m_buffer_.append(skipped.toString());\r
1492         }\r
1493 \r
1494         m_bufferOffset_ = 0;\r
1495     }\r
1496 \r
1497     /**\r
1498      * Returns the current character for forward iteration\r
1499      * @return current character\r
1500      */\r
1501     private int currentChar()\r
1502     {\r
1503         if (m_bufferOffset_ < 0) {\r
1504             m_source_.previous();\r
1505             return m_source_.next();\r
1506         }\r
1507 \r
1508         // m_bufferOffset_ is never 0 in normal circumstances except after a\r
1509         // discontiguous contraction since it is always returned and moved\r
1510         // by 1 when we do nextChar()\r
1511         return m_buffer_.charAt(m_bufferOffset_ - 1);\r
1512     }\r
1513 \r
1514     /**\r
1515      * Method to get the discontiguous collation element within the source.\r
1516      * Note this function will set the position to the appropriate places.\r
1517      * Passed in character offset points to the second combining character\r
1518      * after the start character.\r
1519      * @param collator current collator used\r
1520      * @param entryoffset index to the start character in the contraction table\r
1521      * @return discontiguous collation element offset\r
1522      */\r
1523     private int nextDiscontiguous(RuleBasedCollator collator, int entryoffset)\r
1524     {\r
1525         int offset = entryoffset;\r
1526         boolean multicontraction = false;\r
1527         // since it will be stuffed into this iterator and ran over again\r
1528         if (m_utilSkippedBuffer_ == null) {\r
1529             m_utilSkippedBuffer_ = new StringBuilder();\r
1530         }\r
1531         else {\r
1532             m_utilSkippedBuffer_.setLength(0);\r
1533         }\r
1534         char ch = (char)currentChar();\r
1535         m_utilSkippedBuffer_.append((char)currentChar());\r
1536         // accent after the first character\r
1537         if (m_utilSpecialDiscontiguousBackUp_ == null) {\r
1538             m_utilSpecialDiscontiguousBackUp_ = new Backup();\r
1539         }\r
1540         backupInternalState(m_utilSpecialDiscontiguousBackUp_);\r
1541         char nextch = ch;\r
1542         while (true) {\r
1543             ch = nextch;\r
1544             int ch_int = nextChar();\r
1545             nextch = (char)ch_int;\r
1546             if (ch_int == UCharacterIterator.DONE\r
1547                 || getCombiningClass(nextch) == 0) {\r
1548                 // if there are no more accents to move around\r
1549                 // we don't have to shift previousChar, since we are resetting\r
1550                 // the offset later\r
1551                 if (multicontraction) {\r
1552                     if (ch_int != UCharacterIterator.DONE) {\r
1553                         previousChar(); // backtrack\r
1554                     }\r
1555                     setDiscontiguous(m_utilSkippedBuffer_);\r
1556                     return collator.m_contractionCE_[offset];\r
1557                 }\r
1558                 break;\r
1559             }\r
1560 \r
1561             offset ++; // skip the combining class offset\r
1562             while ((offset < collator.m_contractionIndex_.length) &&\r
1563                    (nextch > collator.m_contractionIndex_[offset])) {\r
1564                 offset ++;\r
1565             }\r
1566 \r
1567             int ce = CE_NOT_FOUND_;\r
1568             if ( offset >= collator.m_contractionIndex_.length)  {\r
1569                 break;\r
1570             }\r
1571             if ( nextch != collator.m_contractionIndex_[offset]\r
1572                  || getCombiningClass(nextch) == getCombiningClass(ch)) {\r
1573                     // unmatched or blocked character\r
1574                 if ( (m_utilSkippedBuffer_.length()!= 1) ||\r
1575                      ((m_utilSkippedBuffer_.charAt(0)!= nextch) &&\r
1576                       (m_bufferOffset_<0) )) { // avoid push to skipped buffer twice\r
1577                     m_utilSkippedBuffer_.append(nextch);\r
1578                 }\r
1579                 offset = entryoffset;  // Restore the offset before checking next character.\r
1580                 continue;\r
1581             }\r
1582             else {\r
1583                 ce = collator.m_contractionCE_[offset];\r
1584             }\r
1585 \r
1586             if (ce == CE_NOT_FOUND_) {\r
1587                 break;\r
1588             }\r
1589             else if (isContractionTag(ce)) {\r
1590                 // this is a multi-contraction\r
1591                 offset = getContractionOffset(collator, ce);\r
1592                 if (collator.m_contractionCE_[offset] != CE_NOT_FOUND_) {\r
1593                     multicontraction = true;\r
1594                     backupInternalState(m_utilSpecialDiscontiguousBackUp_);\r
1595                 }\r
1596             }\r
1597             else {\r
1598                 setDiscontiguous(m_utilSkippedBuffer_);\r
1599                 return ce;\r
1600             }\r
1601         }\r
1602 \r
1603         updateInternalState(m_utilSpecialDiscontiguousBackUp_);\r
1604         // backup is one forward of the base character, we need to move back\r
1605         // one more\r
1606         previousChar();\r
1607         return collator.m_contractionCE_[entryoffset];\r
1608     }\r
1609 \r
1610     /**\r
1611      * Gets the next contraction ce\r
1612      * @param collator collator to use\r
1613      * @param ce current ce\r
1614      * @return ce of the next contraction\r
1615      */\r
1616     private int nextContraction(RuleBasedCollator collator, int ce)\r
1617     {\r
1618         backupInternalState(m_utilSpecialBackUp_);\r
1619         int entryce = collator.m_contractionCE_[getContractionOffset(collator, ce)]; //CE_NOT_FOUND_;\r
1620         while (true) {\r
1621             int entryoffset = getContractionOffset(collator, ce);\r
1622             int offset = entryoffset;\r
1623 \r
1624             if (isEnd()) {\r
1625                 ce = collator.m_contractionCE_[offset];\r
1626                 if (ce == CE_NOT_FOUND_) {\r
1627                     // back up the source over all the chars we scanned going\r
1628                     // into this contraction.\r
1629                     ce = entryce;\r
1630                     updateInternalState(m_utilSpecialBackUp_);\r
1631                 }\r
1632                 break;\r
1633             }\r
1634 \r
1635             // get the discontiguos maximum combining class\r
1636             int maxCC = (collator.m_contractionIndex_[offset] & 0xFF);\r
1637             // checks if all characters have the same combining class\r
1638             byte allSame = (byte)(collator.m_contractionIndex_[offset] >> 8);\r
1639             char ch = (char)nextChar();\r
1640             offset ++;\r
1641             while (ch > collator.m_contractionIndex_[offset]) {\r
1642                 // contraction characters are ordered, skip all smaller\r
1643                 offset ++;\r
1644             }\r
1645 \r
1646             if (ch == collator.m_contractionIndex_[offset]) {\r
1647                 // Found the source string char in the contraction table.\r
1648                 //  Pick up the corresponding CE from the table.\r
1649                 ce = collator.m_contractionCE_[offset];\r
1650             }\r
1651             else {\r
1652                 // Source string char was not in contraction table.\r
1653                 // Unless it is a discontiguous contraction, we are done\r
1654                 int miss = ch;\r
1655                 if(UTF16.isLeadSurrogate(ch)) { // in order to do the proper detection, we\r
1656                     // need to see if we're dealing with a supplementary\r
1657                     miss = UCharacterProperty.getRawSupplementary(ch, (char) nextChar());\r
1658                   }\r
1659                 int sCC;\r
1660                 if (maxCC == 0 || (sCC = getCombiningClass(miss)) == 0\r
1661                     || sCC > maxCC || (allSame != 0 && sCC == maxCC) ||\r
1662                     isEnd()) {\r
1663                     // Contraction can not be discontiguous, back up by one\r
1664                     previousChar();\r
1665                     if(miss > 0xFFFF) {\r
1666                         previousChar();\r
1667                     }\r
1668                     ce = collator.m_contractionCE_[entryoffset];\r
1669                 }\r
1670                 else {\r
1671                     // Contraction is possibly discontiguous.\r
1672                     // find the next character if ch is not a base character\r
1673                     int ch_int = nextChar();\r
1674                     if (ch_int != UCharacterIterator.DONE) {\r
1675                         previousChar();\r
1676                     }\r
1677                     char nextch = (char)ch_int;\r
1678                     if (getCombiningClass(nextch) == 0) {\r
1679                         previousChar();\r
1680                         if(miss > 0xFFFF) {\r
1681                             previousChar();\r
1682                         }    \r
1683                         // base character not part of discontiguous contraction\r
1684                         ce = collator.m_contractionCE_[entryoffset];\r
1685                     }\r
1686                     else {\r
1687                         ce = nextDiscontiguous(collator, entryoffset);\r
1688                     }\r
1689                 }\r
1690             }\r
1691 \r
1692             if (ce == CE_NOT_FOUND_) {\r
1693                 // source did not match the contraction, revert back original\r
1694                 updateInternalState(m_utilSpecialBackUp_);\r
1695                 ce = entryce;\r
1696                 break;\r
1697             }\r
1698 \r
1699             // source was a contraction\r
1700             if (!isContractionTag(ce)) {\r
1701                 break;\r
1702             }\r
1703 \r
1704             // ccontinue looping to check for the remaining contraction.\r
1705             if (collator.m_contractionCE_[entryoffset] != CE_NOT_FOUND_) {\r
1706                 // there are further contractions to be performed, so we store\r
1707                 // the so-far completed ce, so that if we fail in the next\r
1708                 // round we just return this one.\r
1709                 entryce = collator.m_contractionCE_[entryoffset];\r
1710                 backupInternalState(m_utilSpecialBackUp_);\r
1711                 if (m_utilSpecialBackUp_.m_bufferOffset_ >= 0) {\r
1712                     m_utilSpecialBackUp_.m_bufferOffset_ --;\r
1713                 }\r
1714                 else {\r
1715                     m_utilSpecialBackUp_.m_offset_ --;\r
1716                 }\r
1717             }\r
1718         }\r
1719         return ce;\r
1720     }\r
1721 \r
1722     /**\r
1723      * Gets the next ce for long primaries, stuffs the rest of the collation\r
1724      * elements into the ce buffer\r
1725      * @param ce current ce\r
1726      * @return next ce\r
1727      */\r
1728     private int nextLongPrimary(int ce)\r
1729     {\r
1730         m_CEBuffer_[1] = ((ce & 0xFF) << 24)\r
1731             | RuleBasedCollator.CE_CONTINUATION_MARKER_;\r
1732         m_CEBufferOffset_ = 1;\r
1733         m_CEBufferSize_ = 2;\r
1734         m_CEBuffer_[0] = ((ce & 0xFFFF00) << 8) | (CE_BYTE_COMMON_ << 8) |\r
1735             CE_BYTE_COMMON_;\r
1736         return m_CEBuffer_[0];\r
1737     }\r
1738 \r
1739     /**\r
1740      * Gets the number of expansion\r
1741      * @param ce current ce\r
1742      * @return number of expansion\r
1743      */\r
1744     private int getExpansionCount(int ce)\r
1745     {\r
1746         return ce & 0xF;\r
1747     }\r
1748 \r
1749     /**\r
1750      * Gets the next expansion ce and stuffs the rest of the collation elements\r
1751      * into the ce buffer\r
1752      * @param collator current collator\r
1753      * @param ce current ce\r
1754      * @return next expansion ce\r
1755      */\r
1756     private int nextExpansion(RuleBasedCollator collator, int ce)\r
1757     {\r
1758         // NOTE: we can encounter both continuations and expansions in an\r
1759         // expansion!\r
1760         // I have to decide where continuations are going to be dealt with\r
1761         int offset = getExpansionOffset(collator, ce);\r
1762         m_CEBufferSize_ = getExpansionCount(ce);\r
1763         m_CEBufferOffset_ = 1;\r
1764         m_CEBuffer_[0] = collator.m_expansion_[offset];\r
1765         if (m_CEBufferSize_ != 0) {\r
1766             // if there are less than 16 elements in expansion\r
1767             for (int i = 1; i < m_CEBufferSize_; i ++) {\r
1768                 m_CEBuffer_[i] = collator.m_expansion_[offset + i];\r
1769             }\r
1770         }\r
1771         else {\r
1772             // ce are terminated\r
1773             m_CEBufferSize_ = 1;\r
1774             while (collator.m_expansion_[offset] != 0) {\r
1775                 m_CEBuffer_[m_CEBufferSize_ ++] =\r
1776                     collator.m_expansion_[++ offset];\r
1777             }\r
1778         }\r
1779         // in case of one element expansion, we \r
1780         // want to immediately return CEpos\r
1781         if (m_CEBufferSize_ == 1) {\r
1782             m_CEBufferSize_ = 0;\r
1783             m_CEBufferOffset_ = 0;\r
1784         }\r
1785         return m_CEBuffer_[0];\r
1786     }\r
1787     \r
1788     /**\r
1789      * Gets the next digit ce\r
1790      * @param collator current collator\r
1791      * @param ce current collation element\r
1792      * @param cp current codepoint\r
1793      * @return next digit ce\r
1794      */\r
1795     private int nextDigit(RuleBasedCollator collator, int ce, int cp)\r
1796     {\r
1797         // We do a check to see if we want to collate digits as numbers; \r
1798         // if so we generate a custom collation key. Otherwise we pull out \r
1799         // the value stored in the expansion table.\r
1800 \r
1801         if (m_collator_.m_isNumericCollation_){\r
1802             int collateVal = 0;\r
1803             int trailingZeroIndex = 0;\r
1804             boolean nonZeroValReached = false;\r
1805 \r
1806             // I just need a temporary place to store my generated CEs.\r
1807             // icu4c uses a unsigned byte array, i'll use a stringbuffer here\r
1808             // to avoid dealing with the sign problems and array allocation\r
1809             // clear and set initial string buffer length\r
1810             m_utilStringBuffer_.setLength(3);\r
1811         \r
1812             // We parse the source string until we hit a char that's NOT a \r
1813             // digit.\r
1814             // Use this u_charDigitValue. This might be slow because we have \r
1815             // to handle surrogates...\r
1816             int digVal = UCharacter.digit(cp); \r
1817             // if we have arrived here, we have already processed possible \r
1818             // supplementaries that trigered the digit tag -\r
1819             // all supplementaries are marked in the UCA.\r
1820             // We  pad a zero in front of the first element anyways. \r
1821             // This takes care of the (probably) most common case where \r
1822             // people are sorting things followed by a single digit\r
1823             int digIndx = 1;\r
1824             for (;;) {\r
1825                 // Make sure we have enough space.\r
1826                 if (digIndx >= ((m_utilStringBuffer_.length() - 2) << 1)) {\r
1827                     m_utilStringBuffer_.setLength(m_utilStringBuffer_.length() \r
1828                                                   << 1);\r
1829                 }\r
1830                 // Skipping over leading zeroes.        \r
1831                 if (digVal != 0 || nonZeroValReached) {\r
1832                     if (digVal != 0 && !nonZeroValReached) {\r
1833                         nonZeroValReached = true;\r
1834                     }    \r
1835                     // We parse the digit string into base 100 numbers \r
1836                     // (this fits into a byte).\r
1837                     // We only add to the buffer in twos, thus if we are \r
1838                     // parsing an odd character, that serves as the \r
1839                     // 'tens' digit while the if we are parsing an even \r
1840                     // one, that is the 'ones' digit. We dumped the \r
1841                     // parsed base 100 value (collateVal) into a buffer. \r
1842                     // We multiply each collateVal by 2 (to give us room) \r
1843                     // and add 5 (to avoid overlapping magic CE byte \r
1844                     // values). The last byte we subtract 1 to ensure it is \r
1845                     // less than all the other bytes.\r
1846                     if (digIndx % 2 == 1) {\r
1847                         collateVal += digVal;  \r
1848                         // This removes trailing zeroes.\r
1849                         if (collateVal == 0 && trailingZeroIndex == 0) {\r
1850                             trailingZeroIndex = ((digIndx - 1) >>> 1) + 2;\r
1851                         }\r
1852                         else if (trailingZeroIndex != 0) {\r
1853                             trailingZeroIndex = 0;\r
1854                         }\r
1855                         m_utilStringBuffer_.setCharAt(\r
1856                                             ((digIndx - 1) >>> 1) + 2,\r
1857                                             (char)((collateVal << 1) + 6));\r
1858                         collateVal = 0;\r
1859                     }\r
1860                     else {\r
1861                         // We drop the collation value into the buffer so if \r
1862                         // we need to do a "front patch" we don't have to \r
1863                         // check to see if we're hitting the last element.\r
1864                         collateVal = digVal * 10;\r
1865                         m_utilStringBuffer_.setCharAt((digIndx >>> 1) + 2, \r
1866                                                 (char)((collateVal << 1) + 6));\r
1867                     }\r
1868                     digIndx ++;\r
1869                 }\r
1870             \r
1871                 // Get next character.\r
1872                 if (!isEnd()){\r
1873                     backupInternalState(m_utilSpecialBackUp_);\r
1874                     int char32 = nextChar();\r
1875                     char ch = (char)char32;\r
1876                     if (UTF16.isLeadSurrogate(ch)){\r
1877                         if (!isEnd()) {\r
1878                             char trail = (char)nextChar();\r
1879                             if (UTF16.isTrailSurrogate(trail)) {\r
1880                                char32 = UCharacterProperty.getRawSupplementary(\r
1881                                                                    ch, trail);\r
1882                             } \r
1883                             else {\r
1884                                 goBackOne();\r
1885                             }\r
1886                         }\r
1887                     }\r
1888                     \r
1889                     digVal = UCharacter.digit(char32);\r
1890                     if (digVal == -1) {\r
1891                         // Resetting position to point to the next unprocessed \r
1892                         // char. We overshot it when doing our test/set for \r
1893                         // numbers.\r
1894                         updateInternalState(m_utilSpecialBackUp_);\r
1895                         break;\r
1896                     }\r
1897                 } \r
1898                 else {\r
1899                     break;\r
1900                 }\r
1901             }\r
1902         \r
1903             if (nonZeroValReached == false){\r
1904                 digIndx = 2;\r
1905                 m_utilStringBuffer_.setCharAt(2, (char)6);\r
1906             }\r
1907         \r
1908             int endIndex = trailingZeroIndex != 0 ? trailingZeroIndex \r
1909                                              : (digIndx >>> 1) + 2;              \r
1910             if (digIndx % 2 != 0){\r
1911                 // We missed a value. Since digIndx isn't even, stuck too many \r
1912                 // values into the buffer (this is what we get for padding the \r
1913                 // first byte with a zero). "Front-patch" now by pushing all \r
1914                 // nybbles forward.\r
1915                 // Doing it this way ensures that at least 50% of the time \r
1916                 // (statistically speaking) we'll only be doing a single pass \r
1917                 // and optimizes for strings with single digits. I'm just \r
1918                 // assuming that's the more common case.\r
1919                 for (int i = 2; i < endIndex; i ++){\r
1920                     m_utilStringBuffer_.setCharAt(i, \r
1921                         (char)((((((m_utilStringBuffer_.charAt(i) - 6) >>> 1) \r
1922                                   % 10) * 10) \r
1923                                  + (((m_utilStringBuffer_.charAt(i + 1) - 6) \r
1924                                       >>> 1) / 10) << 1) + 6));\r
1925                 }\r
1926                 -- digIndx;\r
1927             }\r
1928         \r
1929             // Subtract one off of the last byte. \r
1930             m_utilStringBuffer_.setCharAt(endIndex - 1, \r
1931                          (char)(m_utilStringBuffer_.charAt(endIndex - 1) - 1));            \r
1932                 \r
1933             // We want to skip over the first two slots in the buffer. \r
1934             // The first slot is reserved for the header byte CODAN_PLACEHOLDER. \r
1935             // The second slot is for the sign/exponent byte: \r
1936             // 0x80 + (decimalPos/2) & 7f.\r
1937             m_utilStringBuffer_.setCharAt(0, (char)RuleBasedCollator.CODAN_PLACEHOLDER);\r
1938             m_utilStringBuffer_.setCharAt(1, \r
1939                                      (char)(0x80 + ((digIndx >>> 1) & 0x7F)));\r
1940         \r
1941             // Now transfer the collation key to our collIterate struct.\r
1942             // The total size for our collation key is endIndx bumped up to the next largest even value divided by two.\r
1943             ce = (((m_utilStringBuffer_.charAt(0) << 8)\r
1944                        // Primary weight \r
1945                        | m_utilStringBuffer_.charAt(1)) \r
1946                                     << RuleBasedCollator.CE_PRIMARY_SHIFT_)\r
1947                        //  Secondary weight \r
1948                        | (RuleBasedCollator.BYTE_COMMON_ \r
1949                           << RuleBasedCollator.CE_SECONDARY_SHIFT_) \r
1950                        | RuleBasedCollator.BYTE_COMMON_; // Tertiary weight.\r
1951             int i = 2; // Reset the index into the buffer.\r
1952             \r
1953             m_CEBuffer_[0] = ce;\r
1954             m_CEBufferSize_ = 1;\r
1955             m_CEBufferOffset_ = 1;\r
1956             while (i < endIndex)\r
1957             {\r
1958                 int primWeight = m_utilStringBuffer_.charAt(i ++) << 8;\r
1959                 if (i < endIndex) {\r
1960                     primWeight |= m_utilStringBuffer_.charAt(i ++);\r
1961                 }\r
1962                 m_CEBuffer_[m_CEBufferSize_ ++] \r
1963                     = (primWeight << RuleBasedCollator.CE_PRIMARY_SHIFT_) \r
1964                       | RuleBasedCollator.CE_CONTINUATION_MARKER_;\r
1965             }\r
1966             return ce;\r
1967         } \r
1968         \r
1969         // no numeric mode, we'll just switch to whatever we stashed and \r
1970         // continue\r
1971         // find the offset to expansion table\r
1972         return collator.m_expansion_[getExpansionOffset(collator, ce)];\r
1973     }\r
1974 \r
1975     /**\r
1976      * Gets the next implicit ce for codepoints\r
1977      * @param codepoint current codepoint\r
1978      * @return implicit ce\r
1979      */\r
1980     private int nextImplicit(int codepoint)\r
1981     {\r
1982         if (!UCharacter.isLegal(codepoint)) {\r
1983             // synwee to check with vladimir on the range of isNonChar()\r
1984             // illegal code value, use completely ignoreable!\r
1985             return IGNORABLE;\r
1986         }\r
1987         int result = RuleBasedCollator.impCEGen_.getImplicitFromCodePoint(codepoint);\r
1988         m_CEBuffer_[0] = (result & RuleBasedCollator.CE_PRIMARY_MASK_)\r
1989                          | 0x00000505;\r
1990         m_CEBuffer_[1] = ((result & 0x0000FFFF) << 16) | 0x000000C0;\r
1991         m_CEBufferOffset_ = 1;\r
1992         m_CEBufferSize_ = 2;\r
1993         return m_CEBuffer_[0];\r
1994     }\r
1995 \r
1996     /**\r
1997      * Returns the next ce associated with the following surrogate characters\r
1998      * @param ch current character\r
1999      * @return ce\r
2000      */\r
2001     private int nextSurrogate(char ch)\r
2002     {\r
2003         int ch_int = nextChar();\r
2004         char nextch = (char)ch_int;\r
2005         if (ch_int != CharacterIterator.DONE &&\r
2006             UTF16.isTrailSurrogate(nextch)) {\r
2007             int codepoint = UCharacterProperty.getRawSupplementary(ch, nextch);\r
2008             return nextImplicit(codepoint);\r
2009         }\r
2010         if (nextch != CharacterIterator.DONE) {\r
2011             previousChar(); // reverts back to the original position\r
2012         }\r
2013         return IGNORABLE; // completely ignorable\r
2014     }\r
2015 \r
2016     /**\r
2017      * Returns the next ce for a hangul character, this is an implicit\r
2018      * calculation\r
2019      * @param collator current collator\r
2020      * @param ch current character\r
2021      * @return hangul ce\r
2022      */\r
2023     private int nextHangul(RuleBasedCollator collator, char ch)\r
2024     {\r
2025         char L = (char)(ch - HANGUL_SBASE_);\r
2026 \r
2027         // divide into pieces\r
2028         // do it in this order since some compilers can do % and / in one\r
2029         // operation\r
2030         char T = (char)(L % HANGUL_TCOUNT_);\r
2031         L /= HANGUL_TCOUNT_;\r
2032         char V = (char)(L % HANGUL_VCOUNT_);\r
2033         L /= HANGUL_VCOUNT_;\r
2034 \r
2035         // offset them\r
2036         L += HANGUL_LBASE_;\r
2037         V += HANGUL_VBASE_;\r
2038         T += HANGUL_TBASE_;\r
2039 \r
2040         // return the first CE, but first put the rest into the expansion\r
2041         // buffer\r
2042         m_CEBufferSize_ = 0;\r
2043         if (!collator.m_isJamoSpecial_) { // FAST PATH\r
2044             m_CEBuffer_[m_CEBufferSize_ ++] =\r
2045                 collator.m_trie_.getLeadValue(L);\r
2046             m_CEBuffer_[m_CEBufferSize_ ++] =\r
2047                 collator.m_trie_.getLeadValue(V);\r
2048 \r
2049             if (T != HANGUL_TBASE_) {\r
2050                 m_CEBuffer_[m_CEBufferSize_ ++] =\r
2051                     collator.m_trie_.getLeadValue(T);\r
2052             }\r
2053             m_CEBufferOffset_ = 1;\r
2054             return m_CEBuffer_[0];\r
2055         }\r
2056         else {\r
2057             // Jamo is Special\r
2058             // Since Hanguls pass the FCD check, it is guaranteed that we\r
2059             // won't be in the normalization buffer if something like this\r
2060             // happens\r
2061             // Move Jamos into normalization buffer\r
2062             m_buffer_.append(L);\r
2063             m_buffer_.append(V);\r
2064             if (T != HANGUL_TBASE_) {\r
2065                 m_buffer_.append(T);\r
2066             }\r
2067             m_FCDLimit_ = m_source_.getIndex();\r
2068             m_FCDStart_ = m_FCDLimit_ - 1;\r
2069             // Indicate where to continue in main input string after\r
2070             // exhausting the buffer\r
2071             return IGNORABLE;\r
2072         }\r
2073     }\r
2074 \r
2075     /**\r
2076      * <p>Special CE management. Expansions, contractions etc...</p>\r
2077      * @param collator can be plain UCA\r
2078      * @param ce current ce\r
2079      * @param ch current character\r
2080      * @return next special ce\r
2081      */\r
2082     private int nextSpecial(RuleBasedCollator collator, int ce, char ch)\r
2083     {\r
2084         int codepoint = ch;\r
2085         Backup entrybackup = m_utilSpecialEntryBackUp_;\r
2086         // this is to handle recursive looping\r
2087         if (entrybackup != null) {\r
2088             m_utilSpecialEntryBackUp_ = null;\r
2089         }\r
2090         else {\r
2091             entrybackup = new Backup();\r
2092         }\r
2093         backupInternalState(entrybackup);\r
2094         try { // forces it to assign m_utilSpecialEntryBackup_\r
2095             while (true) {\r
2096                 // This loop will repeat only in the case of contractions,\r
2097                 // surrogate\r
2098                 switch(RuleBasedCollator.getTag(ce)) {\r
2099                 case CE_NOT_FOUND_TAG_:\r
2100                     // impossible case for icu4j\r
2101                     return ce;\r
2102                 case RuleBasedCollator.CE_SURROGATE_TAG_:\r
2103                     if (isEnd()) {\r
2104                         return IGNORABLE;\r
2105                     }\r
2106                     backupInternalState(m_utilSpecialBackUp_);\r
2107                     char trail = (char)nextChar();\r
2108                     ce = nextSurrogate(collator, ce, trail);\r
2109                     // calculate the supplementary code point value,\r
2110                     // if surrogate was not tailored we go one more round\r
2111                     codepoint =\r
2112                         UCharacterProperty.getRawSupplementary(ch, trail);\r
2113                     break;\r
2114                 case CE_SPEC_PROC_TAG_:\r
2115                     ce = nextSpecialPrefix(collator, ce, entrybackup);\r
2116                     break;\r
2117                 case CE_CONTRACTION_TAG_:\r
2118                     ce = nextContraction(collator, ce);\r
2119                     break;\r
2120                 case CE_LONG_PRIMARY_TAG_:\r
2121                     return nextLongPrimary(ce);\r
2122                 case CE_EXPANSION_TAG_:\r
2123                     return nextExpansion(collator, ce);\r
2124                 case CE_DIGIT_TAG_:\r
2125                     ce = nextDigit(collator, ce, codepoint);\r
2126                     break;\r
2127                     // various implicits optimization\r
2128                 case CE_CJK_IMPLICIT_TAG_:\r
2129                     // 0x3400-0x4DB5, 0x4E00-0x9FA5, 0xF900-0xFA2D\r
2130                     return nextImplicit(codepoint);\r
2131                 case CE_IMPLICIT_TAG_: // everything that is not defined\r
2132                     return nextImplicit(codepoint);\r
2133                 case CE_TRAIL_SURROGATE_TAG_:\r
2134                     return IGNORABLE; // DC00-DFFF broken surrogate\r
2135                 case CE_LEAD_SURROGATE_TAG_:  // D800-DBFF\r
2136                     return nextSurrogate(ch);\r
2137                 case CE_HANGUL_SYLLABLE_TAG_: // AC00-D7AF\r
2138                     return nextHangul(collator, ch);\r
2139                 case CE_CHARSET_TAG_:\r
2140                                     // not yet implemented probably after 1.8\r
2141                     return CE_NOT_FOUND_;\r
2142                 default:\r
2143                     ce = IGNORABLE;\r
2144                     // synwee todo, throw exception or something here.\r
2145                 }\r
2146                 if (!RuleBasedCollator.isSpecial(ce)) {\r
2147                     break;\r
2148                 }\r
2149             }\r
2150         } \r
2151         finally {\r
2152             m_utilSpecialEntryBackUp_ = entrybackup;\r
2153         }\r
2154         return ce;\r
2155     }\r
2156 \r
2157     /**\r
2158      * Special processing is getting a CE that is preceded by a certain prefix.\r
2159      * Currently this is only needed for optimizing Japanese length and\r
2160      * iteration marks. When we encouter a special processing tag, we go\r
2161      * backwards and try to see if we have a match. Contraction tables are used\r
2162      * - so the whole process is not unlike contraction. prefix data is stored\r
2163      * backwards in the table.\r
2164      * @param collator current collator\r
2165      * @param ce current ce\r
2166      * @return previous ce\r
2167      */\r
2168     private int previousSpecialPrefix(RuleBasedCollator collator, int ce)\r
2169     {\r
2170         backupInternalState(m_utilSpecialBackUp_);\r
2171         while (true) {\r
2172             // position ourselves at the begining of contraction sequence\r
2173             int offset = getContractionOffset(collator, ce);\r
2174             int entryoffset = offset;\r
2175             if (isBackwardsStart()) {\r
2176                 ce = collator.m_contractionCE_[offset];\r
2177                 break;\r
2178             }\r
2179             char prevch = (char)previousChar();\r
2180             while (prevch > collator.m_contractionIndex_[offset]) {\r
2181                 // since contraction codepoints are ordered, we skip all that\r
2182                 // are smaller\r
2183                 offset ++;\r
2184             }\r
2185             if (prevch == collator.m_contractionIndex_[offset]) {\r
2186                 ce = collator.m_contractionCE_[offset];\r
2187             }\r
2188             else {\r
2189                 // if there is a completely ignorable code point in the middle\r
2190                 // of a prefix, we need to act as if it's not there assumption:\r
2191                 // 'real' noncharacters (*fffe, *ffff, fdd0-fdef are set to\r
2192                 // zero)\r
2193                 // lone surrogates cannot be set to zero as it would break\r
2194                 // other processing\r
2195                 int isZeroCE = collator.m_trie_.getLeadValue(prevch);\r
2196                 // it's easy for BMP code points\r
2197                 if (isZeroCE == 0) {\r
2198                     continue;\r
2199                 }\r
2200                 else if (UTF16.isTrailSurrogate(prevch)\r
2201                          || UTF16.isLeadSurrogate(prevch)) {\r
2202                     // for supplementary code points, we have to check the next one\r
2203                     // situations where we are going to ignore\r
2204                     // 1. beginning of the string: schar is a lone surrogate\r
2205                     // 2. schar is a lone surrogate\r
2206                     // 3. schar is a trail surrogate in a valid surrogate\r
2207                     //    sequence that is explicitly set to zero.\r
2208                     if (!isBackwardsStart()) {\r
2209                         char lead = (char)previousChar();\r
2210                         if (UTF16.isLeadSurrogate(lead)) {\r
2211                             isZeroCE = collator.m_trie_.getLeadValue(lead);\r
2212                             if (RuleBasedCollator.getTag(isZeroCE)\r
2213                                 == RuleBasedCollator.CE_SURROGATE_TAG_) {\r
2214                                 int finalCE = collator.m_trie_.getTrailValue(\r
2215                                                                       isZeroCE,\r
2216                                                                       prevch);\r
2217                                 if (finalCE == 0) {\r
2218                                     // this is a real, assigned completely\r
2219                                     // ignorable code point\r
2220                                     continue;\r
2221                                 }\r
2222                             }\r
2223                         }\r
2224                         else {\r
2225                             nextChar(); // revert to original offset\r
2226                             // lone surrogate, completely ignorable\r
2227                             continue;\r
2228                         }\r
2229                         nextChar(); // revert to original offset\r
2230                     }\r
2231                     else {\r
2232                          // lone surrogate at the beggining, completely ignorable\r
2233                          continue;\r
2234                     }\r
2235                 }\r
2236 \r
2237                 // char was not in the table. prefix not found\r
2238                 ce = collator.m_contractionCE_[entryoffset];\r
2239             }\r
2240 \r
2241             if (!isSpecialPrefixTag(ce)) {\r
2242                 // char was in the contraction table, and the corresponding ce\r
2243                 // is not a prefix ce.  We found the prefix, break out of loop,\r
2244                 // this ce will end up being returned.\r
2245                 break;\r
2246             }\r
2247         }\r
2248         updateInternalState(m_utilSpecialBackUp_);\r
2249         return ce;\r
2250     }\r
2251 \r
2252     /**\r
2253      * Retrieves the previous contraction ce. To ensure that the backwards and\r
2254      * forwards iteration matches, we take the current region of most possible\r
2255      * match and pass it through the forward iteration. This will ensure that\r
2256      * the obstinate problem of overlapping contractions will not occur.\r
2257      * @param collator current collator\r
2258      * @param ce current ce\r
2259      * @param ch current character\r
2260      * @return previous contraction ce\r
2261      */\r
2262     private int previousContraction(RuleBasedCollator collator, int ce, char ch)\r
2263     {\r
2264         m_utilStringBuffer_.setLength(0);\r
2265         // since we might encounter normalized characters (from the thai\r
2266         // processing) we can't use peekCharacter() here.\r
2267         char prevch = (char)previousChar();\r
2268         boolean atStart = false;\r
2269         // TODO: address the comment above - maybe now we *can* use peekCharacter\r
2270         //while (collator.isUnsafe(ch) || isThaiPreVowel(prevch)) {\r
2271         while (collator.isUnsafe(ch)) {\r
2272             m_utilStringBuffer_.insert(0, ch);\r
2273             ch = prevch;\r
2274             if (isBackwardsStart()) {\r
2275                 atStart = true;\r
2276                 break;\r
2277             }\r
2278             prevch = (char)previousChar();\r
2279         }\r
2280         if (!atStart) {\r
2281             // undo the previousChar() if we didn't reach the beginning \r
2282             nextChar();\r
2283         }\r
2284         // adds the initial base character to the string\r
2285         m_utilStringBuffer_.insert(0, ch);\r
2286 \r
2287         // a new collation element iterator is used to simply things, since\r
2288         // using the current collation element iterator will mean that the\r
2289         // forward and backwards iteration will share and change the same\r
2290         // buffers. it is going to be painful.\r
2291         int originaldecomp = collator.getDecomposition();\r
2292         // for faster access, since string would have been normalized above\r
2293         collator.setDecomposition(Collator.NO_DECOMPOSITION);\r
2294         if (m_utilColEIter_ == null) {\r
2295             m_utilColEIter_ = new CollationElementIterator(\r
2296                                                 m_utilStringBuffer_.toString(),\r
2297                                                 collator);\r
2298         }\r
2299         else {\r
2300             m_utilColEIter_.m_collator_ = collator;\r
2301             m_utilColEIter_.setText(m_utilStringBuffer_.toString());\r
2302         }\r
2303         ce = m_utilColEIter_.next();\r
2304         m_CEBufferSize_ = 0;\r
2305         while (ce != NULLORDER) {\r
2306             if (m_CEBufferSize_ == m_CEBuffer_.length) {\r
2307                 try {\r
2308                     // increasing cebuffer size\r
2309                     int tempbuffer[] = new int[m_CEBuffer_.length + 50];\r
2310                     System.arraycopy(m_CEBuffer_, 0, tempbuffer, 0,\r
2311                                      m_CEBuffer_.length);\r
2312                     m_CEBuffer_ = tempbuffer;\r
2313                 }\r
2314                 catch( MissingResourceException e)\r
2315                 {\r
2316                     throw e;\r
2317                 }\r
2318                 catch (Exception e) {\r
2319                     if(DEBUG){\r
2320                         e.printStackTrace();\r
2321                     }\r
2322                     return NULLORDER;\r
2323                 }\r
2324             }\r
2325             m_CEBuffer_[m_CEBufferSize_ ++] = ce;\r
2326             ce = m_utilColEIter_.next();\r
2327         }\r
2328         collator.setDecomposition(originaldecomp);\r
2329         m_CEBufferOffset_ = m_CEBufferSize_ - 1;\r
2330         return m_CEBuffer_[m_CEBufferOffset_];\r
2331     }\r
2332 \r
2333     /**\r
2334      * Returns the previous long primary ces\r
2335      * @param ce long primary ce\r
2336      * @return previous long primary ces\r
2337      */\r
2338     private int previousLongPrimary(int ce)\r
2339     {\r
2340         m_CEBufferSize_ = 0;\r
2341         m_CEBuffer_[m_CEBufferSize_ ++] =\r
2342             ((ce & 0xFFFF00) << 8) | (CE_BYTE_COMMON_ << 8) | CE_BYTE_COMMON_;\r
2343         m_CEBuffer_[m_CEBufferSize_ ++] = ((ce & 0xFF) << 24)\r
2344             | RuleBasedCollator.CE_CONTINUATION_MARKER_;\r
2345         m_CEBufferOffset_ = m_CEBufferSize_ - 1;\r
2346         return m_CEBuffer_[m_CEBufferOffset_];\r
2347     }\r
2348 \r
2349     /**\r
2350      * Returns the previous expansion ces\r
2351      * @param collator current collator\r
2352      * @param ce current ce\r
2353      * @return previous expansion ce\r
2354      */\r
2355     private int previousExpansion(RuleBasedCollator collator, int ce)\r
2356     {\r
2357         // find the offset to expansion table\r
2358         int offset = getExpansionOffset(collator, ce);\r
2359         m_CEBufferSize_ = getExpansionCount(ce);\r
2360         if (m_CEBufferSize_ != 0) {\r
2361             // less than 16 elements in expansion\r
2362             for (int i = 0; i < m_CEBufferSize_; i ++) {\r
2363                 m_CEBuffer_[i] = collator.m_expansion_[offset + i];\r
2364             }\r
2365 \r
2366         }\r
2367         else {\r
2368             // null terminated ces\r
2369             while (collator.m_expansion_[offset + m_CEBufferSize_] != 0) {\r
2370                 m_CEBuffer_[m_CEBufferSize_] =\r
2371                     collator.m_expansion_[offset + m_CEBufferSize_];\r
2372                 m_CEBufferSize_ ++;\r
2373             }\r
2374         }\r
2375         m_CEBufferOffset_ = m_CEBufferSize_ - 1;\r
2376         return m_CEBuffer_[m_CEBufferOffset_];\r
2377     }\r
2378     \r
2379     /**\r
2380      * Getting the digit collation elements\r
2381      * @param collator\r
2382      * @param ce current collation element\r
2383      * @param ch current code point\r
2384      * @return digit collation element\r
2385      */\r
2386     private int previousDigit(RuleBasedCollator collator, int ce, char ch)\r
2387     {\r
2388         // We do a check to see if we want to collate digits as numbers; if so we generate\r
2389         //  a custom collation key. Otherwise we pull out the value stored in the expansion table.\r
2390         if (m_collator_.m_isNumericCollation_){\r
2391             int leadingZeroIndex = 0;\r
2392             int collateVal = 0;\r
2393             boolean nonZeroValReached = false;\r
2394 \r
2395             // clear and set initial string buffer length\r
2396             m_utilStringBuffer_.setLength(3);\r
2397         \r
2398             // We parse the source string until we hit a char that's NOT a digit\r
2399             // Use this u_charDigitValue. This might be slow because we have to \r
2400             // handle surrogates...\r
2401             int char32 = ch;\r
2402             if (UTF16.isTrailSurrogate(ch)) {\r
2403                 if (!isBackwardsStart()){\r
2404                     char lead = (char)previousChar();\r
2405                     if (UTF16.isLeadSurrogate(lead)) {\r
2406                         char32 = UCharacterProperty.getRawSupplementary(lead,\r
2407                                                                         ch);\r
2408                     } \r
2409                     else {\r
2410                         goForwardOne();\r
2411                     }\r
2412                 }\r
2413             } \r
2414             int digVal = UCharacter.digit(char32);\r
2415             int digIndx = 0;\r
2416             for (;;) {\r
2417                 // Make sure we have enough space.\r
2418                 if (digIndx >= ((m_utilStringBuffer_.length() - 2) << 1)) {\r
2419                     m_utilStringBuffer_.setLength(m_utilStringBuffer_.length() \r
2420                                                   << 1);\r
2421                 }\r
2422                 // Skipping over "trailing" zeroes but we still add to digIndx.\r
2423                 if (digVal != 0 || nonZeroValReached) {\r
2424                     if (digVal != 0 && !nonZeroValReached) {\r
2425                         nonZeroValReached = true;\r
2426                     }\r
2427                 \r
2428                     // We parse the digit string into base 100 numbers (this \r
2429                     // fits into a byte).\r
2430                     // We only add to the buffer in twos, thus if we are \r
2431                     // parsing an odd character, that serves as the 'tens' \r
2432                     // digit while the if we are parsing an even one, that is \r
2433                     // the 'ones' digit. We dumped the parsed base 100 value \r
2434                     // (collateVal) into a buffer. We multiply each collateVal \r
2435                     // by 2 (to give us room) and add 5 (to avoid overlapping \r
2436                     // magic CE byte values). The last byte we subtract 1 to \r
2437                     // ensure it is less than all the other bytes. \r
2438                     // Since we're doing in this reverse we want to put the \r
2439                     // first digit encountered into the ones place and the \r
2440                     // second digit encountered into the tens place.\r
2441                 \r
2442                     if (digIndx % 2 == 1){\r
2443                         collateVal += digVal * 10;\r
2444                     \r
2445                         // This removes leading zeroes.\r
2446                         if (collateVal == 0 && leadingZeroIndex == 0) {\r
2447                            leadingZeroIndex = ((digIndx - 1) >>> 1) + 2;\r
2448                         }\r
2449                         else if (leadingZeroIndex != 0) {\r
2450                             leadingZeroIndex = 0;\r
2451                         }\r
2452                                             \r
2453                         m_utilStringBuffer_.setCharAt(((digIndx - 1) >>> 1) + 2, \r
2454                                                 (char)((collateVal << 1) + 6));\r
2455                         collateVal = 0;\r
2456                     }\r
2457                     else {\r
2458                         collateVal = digVal;    \r
2459                     }\r
2460                 }\r
2461                 digIndx ++;\r
2462             \r
2463                 if (!isBackwardsStart()){\r
2464                     backupInternalState(m_utilSpecialBackUp_);\r
2465                     char32 = previousChar();\r
2466                     if (UTF16.isTrailSurrogate(ch)){\r
2467                         if (!isBackwardsStart()) {\r
2468                             char lead = (char)previousChar();\r
2469                             if (UTF16.isLeadSurrogate(lead)) {\r
2470                                 char32 \r
2471                                     = UCharacterProperty.getRawSupplementary(\r
2472                                                                     lead, ch);\r
2473                             } \r
2474                             else {\r
2475                                 updateInternalState(m_utilSpecialBackUp_);\r
2476                             }\r
2477                         }\r
2478                     }\r
2479                     \r
2480                     digVal = UCharacter.digit(char32);\r
2481                     if (digVal == -1) {\r
2482                         updateInternalState(m_utilSpecialBackUp_);\r
2483                         break;\r
2484                     }\r
2485                 }\r
2486                 else {\r
2487                     break;\r
2488                 }\r
2489             }\r
2490 \r
2491             if (nonZeroValReached == false) {\r
2492                 digIndx = 2;\r
2493                 m_utilStringBuffer_.setCharAt(2, (char)6);\r
2494             }\r
2495             \r
2496             if (digIndx % 2 != 0) {\r
2497                 if (collateVal == 0 && leadingZeroIndex == 0) {\r
2498                     // This removes the leading 0 in a odd number sequence of \r
2499                     // numbers e.g. avery001\r
2500                     leadingZeroIndex = ((digIndx - 1) >>> 1) + 2;\r
2501                 }\r
2502                 else {\r
2503                     // this is not a leading 0, we add it in\r
2504                     m_utilStringBuffer_.setCharAt((digIndx >>> 1) + 2,\r
2505                                                 (char)((collateVal << 1) + 6));\r
2506                     digIndx ++; \r
2507                 }               \r
2508             }\r
2509                      \r
2510             int endIndex = leadingZeroIndex != 0 ? leadingZeroIndex \r
2511                                                : ((digIndx >>> 1) + 2) ;  \r
2512             digIndx = ((endIndex - 2) << 1) + 1; // removing initial zeros         \r
2513             // Subtract one off of the last byte. \r
2514             // Really the first byte here, but it's reversed...\r
2515             m_utilStringBuffer_.setCharAt(2, \r
2516                                     (char)(m_utilStringBuffer_.charAt(2) - 1));          \r
2517             // We want to skip over the first two slots in the buffer. \r
2518             // The first slot is reserved for the header byte CODAN_PLACEHOLDER. \r
2519             // The second slot is for the sign/exponent byte: \r
2520             // 0x80 + (decimalPos/2) & 7f.\r
2521             m_utilStringBuffer_.setCharAt(0, (char)RuleBasedCollator.CODAN_PLACEHOLDER);\r
2522             m_utilStringBuffer_.setCharAt(1, \r
2523                                     (char)(0x80 + ((digIndx >>> 1) & 0x7F)));\r
2524         \r
2525             // Now transfer the collation key to our collIterate struct.\r
2526             // The total size for our collation key is endIndx bumped up to the \r
2527             // next largest even value divided by two.\r
2528             m_CEBufferSize_ = 0;\r
2529             m_CEBuffer_[m_CEBufferSize_ ++] \r
2530                         = (((m_utilStringBuffer_.charAt(0) << 8)\r
2531                             // Primary weight \r
2532                             | m_utilStringBuffer_.charAt(1)) \r
2533                               << RuleBasedCollator.CE_PRIMARY_SHIFT_)\r
2534                             // Secondary weight \r
2535                             | (RuleBasedCollator.BYTE_COMMON_ \r
2536                                << RuleBasedCollator.CE_SECONDARY_SHIFT_)\r
2537                             // Tertiary weight. \r
2538                             | RuleBasedCollator.BYTE_COMMON_; \r
2539              int i = endIndex - 1; // Reset the index into the buffer.\r
2540              while (i >= 2) {\r
2541                 int primWeight = m_utilStringBuffer_.charAt(i --) << 8;\r
2542                 if (i >= 2) {\r
2543                     primWeight |= m_utilStringBuffer_.charAt(i --);\r
2544                 }\r
2545                 m_CEBuffer_[m_CEBufferSize_ ++] \r
2546                     = (primWeight << RuleBasedCollator.CE_PRIMARY_SHIFT_) \r
2547                       | RuleBasedCollator.CE_CONTINUATION_MARKER_;\r
2548              }\r
2549              m_CEBufferOffset_ = m_CEBufferSize_ - 1;\r
2550              return m_CEBuffer_[m_CEBufferOffset_];\r
2551          }\r
2552          else {\r
2553              return collator.m_expansion_[getExpansionOffset(collator, ce)];\r
2554          }\r
2555     } \r
2556 \r
2557     /**\r
2558      * Returns previous hangul ces\r
2559      * @param collator current collator\r
2560      * @param ch current character\r
2561      * @return previous hangul ce\r
2562      */\r
2563     private int previousHangul(RuleBasedCollator collator, char ch)\r
2564     {\r
2565         char L = (char)(ch - HANGUL_SBASE_);\r
2566         // we do it in this order since some compilers can do % and / in one\r
2567         // operation\r
2568         char T = (char)(L % HANGUL_TCOUNT_);\r
2569         L /= HANGUL_TCOUNT_;\r
2570         char V = (char)(L % HANGUL_VCOUNT_);\r
2571         L /= HANGUL_VCOUNT_;\r
2572 \r
2573         // offset them\r
2574         L += HANGUL_LBASE_;\r
2575         V += HANGUL_VBASE_;\r
2576         T += HANGUL_TBASE_;\r
2577 \r
2578         m_CEBufferSize_ = 0;\r
2579         if (!collator.m_isJamoSpecial_) {\r
2580             m_CEBuffer_[m_CEBufferSize_ ++] =\r
2581                 collator.m_trie_.getLeadValue(L);\r
2582             m_CEBuffer_[m_CEBufferSize_ ++] =\r
2583                 collator.m_trie_.getLeadValue(V);\r
2584             if (T != HANGUL_TBASE_) {\r
2585                 m_CEBuffer_[m_CEBufferSize_ ++] =\r
2586                     collator.m_trie_.getLeadValue(T);\r
2587             }\r
2588             m_CEBufferOffset_ = m_CEBufferSize_ - 1;\r
2589             return m_CEBuffer_[m_CEBufferOffset_];\r
2590         }\r
2591         else {\r
2592             // Since Hanguls pass the FCD check, it is guaranteed that we won't\r
2593             // be in the normalization buffer if something like this happens\r
2594             // Move Jamos into normalization buffer\r
2595             m_buffer_.append(L);\r
2596             m_buffer_.append(V);\r
2597             if (T != HANGUL_TBASE_) {\r
2598                 m_buffer_.append(T);\r
2599             }\r
2600 \r
2601             m_FCDStart_ = m_source_.getIndex();\r
2602             m_FCDLimit_ = m_FCDStart_ + 1;\r
2603             return IGNORABLE;\r
2604         }\r
2605     }\r
2606 \r
2607     /**\r
2608      * Gets implicit codepoint ces\r
2609      * @param codepoint current codepoint\r
2610      * @return implicit codepoint ces\r
2611      */\r
2612     private int previousImplicit(int codepoint)\r
2613     {\r
2614         if (!UCharacter.isLegal(codepoint)) {\r
2615             return IGNORABLE; // illegal code value, completely ignoreable!\r
2616         }\r
2617         int result = RuleBasedCollator.impCEGen_.getImplicitFromCodePoint(codepoint);\r
2618         m_CEBufferSize_ = 2;\r
2619         m_CEBufferOffset_ = 1;\r
2620         m_CEBuffer_[0] = (result & RuleBasedCollator.CE_PRIMARY_MASK_)\r
2621                          | 0x00000505;\r
2622         m_CEBuffer_[1] = ((result & 0x0000FFFF) << 16) | 0x000000C0;\r
2623         return m_CEBuffer_[1];\r
2624     }\r
2625 \r
2626     /**\r
2627      * Gets the previous surrogate ce\r
2628      * @param ch current character\r
2629      * @return previous surrogate ce\r
2630      */\r
2631     private int previousSurrogate(char ch)\r
2632     {\r
2633         if (isBackwardsStart()) {\r
2634             // we are at the start of the string, wrong place to be at\r
2635             return IGNORABLE;\r
2636         }\r
2637         char prevch = (char)previousChar();\r
2638         // Handles Han and Supplementary characters here.\r
2639         if (UTF16.isLeadSurrogate(prevch)) {\r
2640             return previousImplicit(\r
2641                           UCharacterProperty.getRawSupplementary(prevch, ch));\r
2642         }\r
2643         if (prevch != CharacterIterator.DONE) {\r
2644             nextChar();\r
2645         }\r
2646         return IGNORABLE; // completely ignorable\r
2647     }\r
2648 \r
2649     /**\r
2650      * <p>Special CE management. Expansions, contractions etc...</p>\r
2651      * @param collator can be plain UCA\r
2652      * @param ce current ce\r
2653      * @param ch current character\r
2654      * @return previous special ce\r
2655      */\r
2656     private int previousSpecial(RuleBasedCollator collator, int ce, char ch)\r
2657     {\r
2658         while(true) {\r
2659             // the only ces that loops are thai, special prefix and\r
2660             // contractions\r
2661             switch (RuleBasedCollator.getTag(ce)) {\r
2662             case CE_NOT_FOUND_TAG_:  // this tag always returns\r
2663                 return ce;\r
2664             case RuleBasedCollator.CE_SURROGATE_TAG_:\r
2665                                 // essentialy a disengaged lead surrogate. a broken\r
2666                                 // sequence was encountered and this is an error\r
2667                 return IGNORABLE;\r
2668             case CE_SPEC_PROC_TAG_:\r
2669                 ce = previousSpecialPrefix(collator, ce);\r
2670                 break;\r
2671             case CE_CONTRACTION_TAG_:\r
2672                 // may loop for first character e.g. "0x0f71" for english\r
2673                 if (isBackwardsStart()) {\r
2674                     // start of string or this is not the end of any contraction\r
2675                     ce = collator.m_contractionCE_[\r
2676                                             getContractionOffset(collator, ce)];\r
2677                     break;\r
2678                 }\r
2679                 return previousContraction(collator, ce, ch); // else\r
2680             case CE_LONG_PRIMARY_TAG_:\r
2681                 return previousLongPrimary(ce);\r
2682             case CE_EXPANSION_TAG_: // always returns\r
2683                 return previousExpansion(collator, ce);\r
2684             case CE_DIGIT_TAG_:\r
2685                 ce = previousDigit(collator, ce, ch);\r
2686                 break;\r
2687             case CE_HANGUL_SYLLABLE_TAG_: // AC00-D7AF\r
2688                 return previousHangul(collator, ch);\r
2689             case CE_LEAD_SURROGATE_TAG_:  // D800-DBFF\r
2690                 return IGNORABLE; // broken surrogate sequence\r
2691             case CE_TRAIL_SURROGATE_TAG_: // DC00-DFFF\r
2692                 return previousSurrogate(ch);\r
2693             case CE_CJK_IMPLICIT_TAG_:\r
2694                 // 0x3400-0x4DB5, 0x4E00-0x9FA5, 0xF900-0xFA2D\r
2695                 return previousImplicit(ch);\r
2696             case CE_IMPLICIT_TAG_: // everything that is not defined\r
2697                 // UCA is filled with these. Tailorings are NOT_FOUND\r
2698                 return previousImplicit(ch);\r
2699             case CE_CHARSET_TAG_: // this tag always returns\r
2700                 return CE_NOT_FOUND_;\r
2701             default: // this tag always returns\r
2702                 ce = IGNORABLE;\r
2703             }\r
2704             if (!RuleBasedCollator.isSpecial(ce)) {\r
2705                 break;\r
2706             }\r
2707         }\r
2708         return ce;\r
2709     }\r
2710 \r
2711     /**\r
2712      * GET IMPLICIT PRIMARY WEIGHTS\r
2713      * @param cp codepoint\r
2714      * @param value is left justified primary key\r
2715      */\r
2716 //    private static final int getImplicitPrimary(int cp)\r
2717 //    {\r
2718 //        cp = swapCJK(cp);\r
2719 //\r
2720 //        //if (DEBUG) System.out.println("CJK swapped: " + Utility.hex(cp));\r
2721 //        // we now have a range of numbers from 0 to 21FFFF.\r
2722 //        // we must skip all 00, 01, 02 bytes, so most bytes have 253 values\r
2723 //        // we must leave a gap of 01 between all values of the last byte, so\r
2724 //        // the last byte has 126 values (3 byte case)\r
2725 //        // we shift so that HAN all has the same first primary, for\r
2726 //        // compression.\r
2727 //        // for the 4 byte case, we make the gap as large as we can fit.\r
2728 //        // Three byte forms are EC xx xx, ED xx xx, EE xx xx (with a gap of 1)\r
2729 //        // Four byte forms (most supplementaries) are EF xx xx xx (with a gap\r
2730 //        // of LAST2_MULTIPLIER == 14)\r
2731 //\r
2732 //        int last0 = cp - RuleBasedCollator.IMPLICIT_4BYTE_BOUNDARY_;\r
2733 //        if (last0 < 0) {\r
2734 //            int last1 = cp / RuleBasedCollator.LAST_COUNT_;\r
2735 //            last0 = cp % RuleBasedCollator.LAST_COUNT_;\r
2736 //\r
2737 //            int last2 = last1 / RuleBasedCollator.OTHER_COUNT_;\r
2738 //            last1 %= RuleBasedCollator.OTHER_COUNT_;\r
2739 //            return RuleBasedCollator.IMPLICIT_BASE_3BYTE_ + (last2 << 24)\r
2740 //                   + (last1 << 16)\r
2741 //                   + ((last0 * RuleBasedCollator.LAST_MULTIPLIER_) << 8);\r
2742 //        }\r
2743 //        else {\r
2744 //            int last1 = last0 / RuleBasedCollator.LAST_COUNT2_;\r
2745 //            last0 %= RuleBasedCollator.LAST_COUNT2_;\r
2746 //\r
2747 //            int last2 = last1 / RuleBasedCollator.OTHER_COUNT_;\r
2748 //            last1 %= RuleBasedCollator.OTHER_COUNT_;\r
2749 //\r
2750 //            int last3 = last2 / RuleBasedCollator.OTHER_COUNT_;\r
2751 //            last2 %= RuleBasedCollator.OTHER_COUNT_;\r
2752 //            return RuleBasedCollator.IMPLICIT_BASE_4BYTE_ + (last3 << 24)\r
2753 //                   + (last2 << 16) + (last1 << 8)\r
2754 //                   + (last0 * RuleBasedCollator.LAST2_MULTIPLIER_);\r
2755 //        }\r
2756 //    }\r
2757 \r
2758 //    /**\r
2759 //     * Swapping CJK characters for implicit ces\r
2760 //     * @param cp codepoint CJK\r
2761 //     * @return swapped result\r
2762 //     */\r
2763 //    private static final int swapCJK(int cp)\r
2764 //    {\r
2765 //        if (cp >= CJK_BASE_) {\r
2766 //            if (cp < CJK_LIMIT_) {\r
2767 //                return cp - CJK_BASE_;\r
2768 //            }\r
2769 //            if (cp < CJK_COMPAT_USED_BASE_) {\r
2770 //                return cp + NON_CJK_OFFSET_;\r
2771 //            }\r
2772 //            if (cp < CJK_COMPAT_USED_LIMIT_) {\r
2773 //                return cp - CJK_COMPAT_USED_BASE_ + (CJK_LIMIT_ - CJK_BASE_);\r
2774 //            }\r
2775 //            if (cp < CJK_B_BASE_) {\r
2776 //                return cp + NON_CJK_OFFSET_;\r
2777 //            }\r
2778 //            if (cp < CJK_B_LIMIT_) {\r
2779 //                return cp; // non-BMP-CJK\r
2780 //            }\r
2781 //            return cp + NON_CJK_OFFSET_; // non-CJK\r
2782 //        }\r
2783 //        if (cp < CJK_A_BASE_) {\r
2784 //            return cp + NON_CJK_OFFSET_;\r
2785 //        }\r
2786 //        if (cp < CJK_A_LIMIT_) {\r
2787 //            return cp - CJK_A_BASE_ + (CJK_LIMIT_ - CJK_BASE_)\r
2788 //                   + (CJK_COMPAT_USED_LIMIT_ - CJK_COMPAT_USED_BASE_);\r
2789 //        }\r
2790 //        return cp + NON_CJK_OFFSET_; // non-CJK\r
2791 //    }\r
2792     \r
2793 //    /** \r
2794 //     * Gets a character from the source string at a given offset.\r
2795 //     * Handles both normal and iterative cases.\r
2796 //     * No error checking and does not access the normalization buffer \r
2797 //     * - caller beware!\r
2798 //     * @param offset offset from current position which character is to be \r
2799 //     *               retrieved\r
2800 //     * @return character at current position + offset\r
2801 //     */\r
2802 //    private char peekCharacter(int offset) \r
2803 //    {\r
2804 //        if (offset != 0) {\r
2805 //            int currentoffset = m_source_.getIndex();\r
2806 //            m_source_.setIndex(currentoffset + offset);\r
2807 //            char result = (char)m_source_.current();\r
2808 //            m_source_.setIndex(currentoffset);\r
2809 //            return result;\r
2810 //        } \r
2811 //        else {\r
2812 //            return (char)m_source_.current();\r
2813 //        }\r
2814 //    }\r
2815 \r
2816     /**\r
2817      * Moves back 1 position in the source string. This is slightly less \r
2818      * complicated than previousChar in that it doesn't normalize while \r
2819      * moving back. Boundary checks are not performed.\r
2820      * This method is to be used with caution, with the assumption that \r
2821      * moving back one position will not exceed the source limits.\r
2822      * Use only with nextChar() and never call this API twice in a row without\r
2823      * nextChar() in the middle.\r
2824      */\r
2825     private void goBackOne() \r
2826     {\r
2827         if (m_bufferOffset_ >= 0) {\r
2828             m_bufferOffset_ --;\r
2829         }\r
2830         else {\r
2831             m_source_.setIndex(m_source_.getIndex() - 1);\r
2832         }\r
2833     }\r
2834     \r
2835     /**\r
2836      * Moves forward 1 position in the source string. This is slightly less \r
2837      * complicated than nextChar in that it doesn't normalize while \r
2838      * moving back. Boundary checks are not performed.\r
2839      * This method is to be used with caution, with the assumption that \r
2840      * moving back one position will not exceed the source limits.\r
2841      * Use only with previousChar() and never call this API twice in a row \r
2842      * without previousChar() in the middle.\r
2843      */\r
2844     private void goForwardOne() \r
2845     {\r
2846         if (m_bufferOffset_ < 0) {\r
2847             // we're working on the source and not normalizing. fast path.\r
2848             // note Thai pre-vowel reordering uses buffer too\r
2849             m_source_.setIndex(m_source_.getIndex() + 1);\r
2850         }\r
2851         else {\r
2852             // we are in the buffer, buffer offset will never be 0 here\r
2853             m_bufferOffset_ ++;\r
2854         }\r
2855     }\r
2856 }\r