001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.io.input;
018
019 import java.io.Reader;
020 import java.io.Serializable;
021
022 /**
023 * {@link Reader} implementation that can read from String, StringBuffer,
024 * StringBuilder or CharBuffer.
025 * <p>
026 * <strong>Note:</strong> Supports {@link #mark(int)} and {@link #reset()}.
027 *
028 * @version $Revision: 610516 $ $Date: 2008-01-09 19:05:05 +0000 (Wed, 09 Jan 2008) $
029 * @since Commons IO 1.4
030 */
031 public class CharSequenceReader extends Reader implements Serializable {
032
033 private final CharSequence charSequence;
034 private int idx;
035 private int mark;
036
037 /**
038 * Construct a new instance with the specified character sequence.
039 *
040 * @param charSequence The character sequence, may be <code>null</code>
041 */
042 public CharSequenceReader(CharSequence charSequence) {
043 this.charSequence = (charSequence != null ? charSequence : "");
044 }
045
046 /**
047 * Close resets the file back to the start and removes any marked position.
048 */
049 public void close() {
050 idx = 0;
051 mark = 0;
052 }
053
054 /**
055 * Mark the current position.
056 *
057 * @param readAheadLimit ignored
058 */
059 public void mark(int readAheadLimit) {
060 mark = idx;
061 }
062
063 /**
064 * Mark is supported (returns true).
065 *
066 * @return <code>true</code>
067 */
068 public boolean markSupported() {
069 return true;
070 }
071
072 /**
073 * Read a single character.
074 *
075 * @return the next character from the character sequence
076 * or -1 if the end has been reached.
077 */
078 public int read() {
079 if (idx >= charSequence.length()) {
080 return -1;
081 } else {
082 return charSequence.charAt(idx++);
083 }
084 }
085
086 /**
087 * Read the sepcified number of characters into the array.
088 *
089 * @param array The array to store the characters in
090 * @param offset The starting position in the array to store
091 * @param length The maximum number of characters to read
092 * @return The number of characters read or -1 if there are
093 * no more
094 */
095 public int read(char[] array, int offset, int length) {
096 if (idx >= charSequence.length()) {
097 return -1;
098 }
099 if (array == null) {
100 throw new NullPointerException("Character array is missing");
101 }
102 if (length < 0 || (offset + length) > array.length) {
103 throw new IndexOutOfBoundsException("Array Size=" + array.length +
104 ", offset=" + offset + ", length=" + length);
105 }
106 int count = 0;
107 for (int i = 0; i < length; i++) {
108 int c = read();
109 if (c == -1) {
110 return count;
111 }
112 array[offset + i] = (char)c;
113 count++;
114 }
115 return count;
116 }
117
118 /**
119 * Reset the reader to the last marked position (or the beginning if
120 * mark has not been called).
121 */
122 public void reset() {
123 idx = mark;
124 }
125
126 /**
127 * Skip the specified number of characters.
128 *
129 * @param n The number of characters to skip
130 * @return The actual number of characters skipped
131 */
132 public long skip(long n) {
133 if (n < 0) {
134 throw new IllegalArgumentException(
135 "Number of characters to skip is less than zero: " + n);
136 }
137 if (idx >= charSequence.length()) {
138 return -1;
139 }
140 int dest = (int)Math.min(charSequence.length(), (idx + n));
141 int count = dest - idx;
142 idx = dest;
143 return count;
144 }
145
146 /**
147 * Return a String representation of the underlying
148 * character sequence.
149 *
150 * @return The contents of the character sequence
151 */
152 public String toString() {
153 return charSequence.toString();
154 }
155 }