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 $Id: CharSequenceReader.java 1304052 2012-03-22 20:55:29Z ggregory $
029 * @since 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 @Override
050 public void close() {
051 idx = 0;
052 mark = 0;
053 }
054
055 /**
056 * Mark the current position.
057 *
058 * @param readAheadLimit ignored
059 */
060 @Override
061 public void mark(int readAheadLimit) {
062 mark = idx;
063 }
064
065 /**
066 * Mark is supported (returns true).
067 *
068 * @return <code>true</code>
069 */
070 @Override
071 public boolean markSupported() {
072 return true;
073 }
074
075 /**
076 * Read a single character.
077 *
078 * @return the next character from the character sequence
079 * or -1 if the end has been reached.
080 */
081 @Override
082 public int read() {
083 if (idx >= charSequence.length()) {
084 return -1;
085 } else {
086 return charSequence.charAt(idx++);
087 }
088 }
089
090 /**
091 * Read the sepcified number of characters into the array.
092 *
093 * @param array The array to store the characters in
094 * @param offset The starting position in the array to store
095 * @param length The maximum number of characters to read
096 * @return The number of characters read or -1 if there are
097 * no more
098 */
099 @Override
100 public int read(char[] array, int offset, int length) {
101 if (idx >= charSequence.length()) {
102 return -1;
103 }
104 if (array == null) {
105 throw new NullPointerException("Character array is missing");
106 }
107 if (length < 0 || offset < 0 || offset + length > array.length) {
108 throw new IndexOutOfBoundsException("Array Size=" + array.length +
109 ", offset=" + offset + ", length=" + length);
110 }
111 int count = 0;
112 for (int i = 0; i < length; i++) {
113 int c = read();
114 if (c == -1) {
115 return count;
116 }
117 array[offset + i] = (char)c;
118 count++;
119 }
120 return count;
121 }
122
123 /**
124 * Reset the reader to the last marked position (or the beginning if
125 * mark has not been called).
126 */
127 @Override
128 public void reset() {
129 idx = mark;
130 }
131
132 /**
133 * Skip the specified number of characters.
134 *
135 * @param n The number of characters to skip
136 * @return The actual number of characters skipped
137 */
138 @Override
139 public long skip(long n) {
140 if (n < 0) {
141 throw new IllegalArgumentException(
142 "Number of characters to skip is less than zero: " + n);
143 }
144 if (idx >= charSequence.length()) {
145 return -1;
146 }
147 int dest = (int)Math.min(charSequence.length(), idx + n);
148 int count = dest - idx;
149 idx = dest;
150 return count;
151 }
152
153 /**
154 * Return a String representation of the underlying
155 * character sequence.
156 *
157 * @return The contents of the character sequence
158 */
159 @Override
160 public String toString() {
161 return charSequence.toString();
162 }
163 }