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 }