001: /*
002: *******************************************************************************
003: * Copyright (C) 1996-2005, International Business Machines Corporation and *
004: * others. All Rights Reserved. *
005: *******************************************************************************
006: */
007: package com.ibm.icu.impl;
008:
009: import com.ibm.icu.text.*;
010: import com.ibm.icu.text.Replaceable;
011: import com.ibm.icu.text.ReplaceableString;
012: import com.ibm.icu.text.UTF16;
013:
014: /**
015: * DLF docs must define behavior when Replaceable is mutated underneath
016: * the iterator.
017: *
018: * This and ICUCharacterIterator share some code, maybe they should share
019: * an implementation, or the common state and implementation should be
020: * moved up into UCharacterIterator.
021: *
022: * What are first, last, and getBeginIndex doing here?!?!?!
023: */
024: public class ReplaceableUCharacterIterator extends UCharacterIterator {
025:
026: // public constructor ------------------------------------------------------
027:
028: /**
029: * Public constructor
030: * @param replaceable text which the iterator will be based on
031: */
032: public ReplaceableUCharacterIterator(Replaceable replaceable) {
033: if (replaceable == null) {
034: throw new IllegalArgumentException();
035: }
036: this .replaceable = replaceable;
037: this .currentIndex = 0;
038: }
039:
040: /**
041: * Public constructor
042: * @param str text which the iterator will be based on
043: */
044: public ReplaceableUCharacterIterator(String str) {
045: if (str == null) {
046: throw new IllegalArgumentException();
047: }
048: this .replaceable = new ReplaceableString(str);
049: this .currentIndex = 0;
050: }
051:
052: /**
053: * Public constructor
054: * @param buf buffer of text on which the iterator will be based
055: */
056: public ReplaceableUCharacterIterator(StringBuffer buf) {
057: if (buf == null) {
058: throw new IllegalArgumentException();
059: }
060: this .replaceable = new ReplaceableString(buf);
061: this .currentIndex = 0;
062: }
063:
064: // public methods ----------------------------------------------------------
065:
066: /**
067: * Creates a copy of this iterator, does not clone the underlying
068: * <code>Replaceable</code>object
069: * @return copy of this iterator
070: */
071: public Object clone() {
072: try {
073: return super .clone();
074: } catch (CloneNotSupportedException e) {
075: return null; // never invoked
076: }
077: }
078:
079: /**
080: * Returns the current UTF16 character.
081: * @return current UTF16 character
082: */
083: public int current() {
084: if (currentIndex < replaceable.length()) {
085: return replaceable.charAt(currentIndex);
086: }
087: return DONE;
088: }
089:
090: /**
091: * Returns the current codepoint
092: * @return current codepoint
093: */
094: public int currentCodePoint() {
095: // cannot use charAt due to it different
096: // behaviour when index is pointing at a
097: // trail surrogate, check for surrogates
098:
099: int ch = current();
100: if (UTF16.isLeadSurrogate((char) ch)) {
101: // advance the index to get the next code point
102: next();
103: // due to post increment semantics current() after next()
104: // actually returns the next char which is what we want
105: int ch2 = current();
106: // current should never change the current index so back off
107: previous();
108:
109: if (UTF16.isTrailSurrogate((char) ch2)) {
110: // we found a surrogate pair
111: return UCharacterProperty.getRawSupplementary(
112: (char) ch, (char) ch2);
113: }
114: }
115: return ch;
116: }
117:
118: /**
119: * Returns the length of the text
120: * @return length of the text
121: */
122: public int getLength() {
123: return replaceable.length();
124: }
125:
126: /**
127: * Gets the current currentIndex in text.
128: * @return current currentIndex in text.
129: */
130: public int getIndex() {
131: return currentIndex;
132: }
133:
134: /**
135: * Returns next UTF16 character and increments the iterator's currentIndex by 1.
136: * If the resulting currentIndex is greater or equal to the text length, the
137: * currentIndex is reset to the text length and a value of DONECODEPOINT is
138: * returned.
139: * @return next UTF16 character in text or DONE if the new currentIndex is off the
140: * end of the text range.
141: */
142: public int next() {
143: if (currentIndex < replaceable.length()) {
144: return replaceable.charAt(currentIndex++);
145: }
146: return DONE;
147: }
148:
149: /**
150: * Returns previous UTF16 character and decrements the iterator's currentIndex by
151: * 1.
152: * If the resulting currentIndex is less than 0, the currentIndex is reset to 0 and a
153: * value of DONECODEPOINT is returned.
154: * @return next UTF16 character in text or DONE if the new currentIndex is off the
155: * start of the text range.
156: */
157: public int previous() {
158: if (currentIndex > 0) {
159: return replaceable.charAt(--currentIndex);
160: }
161: return DONE;
162: }
163:
164: /**
165: * <p>Sets the currentIndex to the specified currentIndex in the text and returns that
166: * single UTF16 character at currentIndex.
167: * This assumes the text is stored as 16-bit code units.</p>
168: * @param currentIndex the currentIndex within the text.
169: * @exception IllegalArgumentException is thrown if an invalid currentIndex is
170: * supplied. i.e. currentIndex is out of bounds.
171: * @returns the character at the specified currentIndex or DONE if the specified
172: * currentIndex is equal to the end of the text.
173: */
174: public void setIndex(int currentIndex)
175: throws IndexOutOfBoundsException {
176: if (currentIndex < 0 || currentIndex > replaceable.length()) {
177: throw new IndexOutOfBoundsException();
178: }
179: this .currentIndex = currentIndex;
180: }
181:
182: public int getText(char[] fillIn, int offset) {
183: int length = replaceable.length();
184: if (offset < 0 || offset + length > fillIn.length) {
185: throw new IndexOutOfBoundsException(Integer
186: .toString(length));
187: }
188: replaceable.getChars(0, length, fillIn, offset);
189: return length;
190: }
191:
192: // private data members ----------------------------------------------------
193:
194: /**
195: * Replacable object
196: */
197: private Replaceable replaceable;
198: /**
199: * Current currentIndex
200: */
201: private int currentIndex;
202:
203: }
|