    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: 659817 $ $Date: 2008-05-24 14:23:10 +0100 (Sat, 24 May 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        @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 + 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    }