~ubuntu-branches/ubuntu/vivid/icu4j-4.4/vivid

« back to all changes in this revision

Viewing changes to main/classes/collate/src/com/ibm/icu/text/CollationElementIterator.java

  • Committer: Bazaar Package Importer
  • Author(s): Niels Thykier
  • Date: 2011-08-02 15:50:33 UTC
  • Revision ID: james.westby@ubuntu.com-20110802155033-itjzsl21y2lqdonn
Tags: upstream-4.4.2
ImportĀ upstreamĀ versionĀ 4.4.2

Show diffs side-by-side

added added

removed removed

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