1 /*
   2  * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 /*
  27  * (C) Copyright IBM Corp. 2003 - All Rights Reserved
  28  *
  29  * The original version of this source code and documentation is
  30  * copyrighted and owned by IBM. These materials are provided
  31  * under terms of a License Agreement between IBM and Sun.
  32  * This technology is protected by multiple US and International
  33  * patents. This notice and attribution to IBM may not be removed.
  34  */
  35 
  36 package sun.text;
  37 
  38 import java.text.CharacterIterator;
  39 
  40 public abstract class CodePointIterator {
  41     public static final int DONE = -1;
  42 
  43     public abstract void setToStart();
  44     public abstract void setToLimit();
  45 
  46     public abstract int next();
  47     public abstract int prev();
  48 
  49     public abstract int charIndex();
  50 
  51     public static CodePointIterator create(char[] text) {
  52         return new CharArrayCodePointIterator(text);
  53     }
  54 
  55     public static CodePointIterator create(char[] text, int start, int limit) {
  56         return new CharArrayCodePointIterator(text, start, limit);
  57     }
  58 
  59     public static CodePointIterator create(CharSequence text) {
  60         return new CharSequenceCodePointIterator(text);
  61     }
  62 
  63     public static CodePointIterator create(CharacterIterator iter) {
  64         return new CharacterIteratorCodePointIterator(iter);
  65     }
  66 }
  67 
  68 final class CharArrayCodePointIterator extends CodePointIterator {
  69     private char[] text;
  70     private int start;
  71     private int limit;
  72     private int index;
  73 
  74     public CharArrayCodePointIterator(char[] text) {
  75         this.text = text;
  76         this.limit = text.length;
  77     }
  78 
  79     public CharArrayCodePointIterator(char[] text, int start, int limit) {
  80         if (start < 0 || limit < start || limit > text.length) {
  81             throw new IllegalArgumentException();
  82         }
  83 
  84         this.text = text;
  85         this.start = this.index = start;
  86         this.limit = limit;
  87     }
  88 
  89     public void setToStart() {
  90         index = start;
  91     }
  92 
  93     public void setToLimit() {
  94         index = limit;
  95     }
  96 
  97     public int next() {
  98         if (index < limit) {
  99             char cp1 = text[index++];
 100             if (Character.isHighSurrogate(cp1) && index < limit) {
 101                 char cp2 = text[index];
 102                 if (Character.isLowSurrogate(cp2)) {
 103                     ++index;
 104                     return Character.toCodePoint(cp1, cp2);
 105                 }
 106             }
 107             return cp1;
 108         }
 109         return DONE;
 110     }
 111 
 112     public int prev() {
 113         if (index > start) {
 114             char cp2 = text[--index];
 115             if (Character.isLowSurrogate(cp2) && index > start) {
 116                 char cp1 = text[index - 1];
 117                 if (Character.isHighSurrogate(cp1)) {
 118                     --index;
 119                     return Character.toCodePoint(cp1, cp2);
 120                 }
 121             }
 122             return cp2;
 123         }
 124         return DONE;
 125     }
 126 
 127     public int charIndex() {
 128         return index;
 129     }
 130 }
 131 
 132 final class CharSequenceCodePointIterator extends CodePointIterator {
 133     private CharSequence text;
 134     private int index;
 135 
 136     public CharSequenceCodePointIterator(CharSequence text) {
 137         this.text = text;
 138     }
 139 
 140     public void setToStart() {
 141         index = 0;
 142     }
 143 
 144     public void setToLimit() {
 145         index = text.length();
 146     }
 147 
 148     public int next() {
 149         if (index < text.length()) {
 150             char cp1 = text.charAt(index++);
 151             if (Character.isHighSurrogate(cp1) && index < text.length()) {
 152                 char cp2 = text.charAt(index+1);
 153                 if (Character.isLowSurrogate(cp2)) {
 154                     ++index;
 155                     return Character.toCodePoint(cp1, cp2);
 156                 }
 157             }
 158             return cp1;
 159         }
 160         return DONE;
 161     }
 162 
 163     public int prev() {
 164         if (index > 0) {
 165             char cp2 = text.charAt(--index);
 166             if (Character.isLowSurrogate(cp2) && index > 0) {
 167                 char cp1 = text.charAt(index - 1);
 168                 if (Character.isHighSurrogate(cp1)) {
 169                     --index;
 170                     return Character.toCodePoint(cp1, cp2);
 171                 }
 172             }
 173             return cp2;
 174         }
 175         return DONE;
 176     }
 177 
 178     public int charIndex() {
 179         return index;
 180     }
 181 }
 182 
 183 // note this has different iteration semantics than CharacterIterator
 184 final class CharacterIteratorCodePointIterator extends CodePointIterator {
 185     private CharacterIterator iter;
 186 
 187     public CharacterIteratorCodePointIterator(CharacterIterator iter) {
 188         this.iter = iter;
 189     }
 190 
 191     public void setToStart() {
 192         iter.setIndex(iter.getBeginIndex());
 193     }
 194 
 195     public void setToLimit() {
 196         iter.setIndex(iter.getEndIndex());
 197     }
 198 
 199     public int next() {
 200         char cp1 = iter.current();
 201         if (cp1 != CharacterIterator.DONE) {
 202             char cp2 = iter.next();
 203             if (Character.isHighSurrogate(cp1) && cp2 != CharacterIterator.DONE) {
 204                 if (Character.isLowSurrogate(cp2)) {
 205                     iter.next();
 206                     return Character.toCodePoint(cp1, cp2);
 207                 }
 208             }
 209             return cp1;
 210         }
 211         return DONE;
 212     }
 213 
 214     public int prev() {
 215         char cp2 = iter.previous();
 216         if (cp2 != CharacterIterator.DONE) {
 217             if (Character.isLowSurrogate(cp2)) {
 218                 char cp1 = iter.previous();
 219                 if (Character.isHighSurrogate(cp1)) {
 220                     return Character.toCodePoint(cp1, cp2);
 221                 }
 222                 iter.next();
 223             }
 224             return cp2;
 225         }
 226         return DONE;
 227     }
 228 
 229     public int charIndex() {
 230         return iter.getIndex();
 231     }
 232 }