001: ////////////////////////////////////////////////////////////////////////////////
002: // checkstyle: Checks Java source code for adherence to a set of rules.
003: // Copyright (C) 2001-2007 Oliver Burn
004: //
005: // This library is free software; you can redistribute it and/or
006: // modify it under the terms of the GNU Lesser General Public
007: // License as published by the Free Software Foundation; either
008: // version 2.1 of the License, or (at your option) any later version.
009: //
010: // This library is distributed in the hope that it will be useful,
011: // but WITHOUT ANY WARRANTY; without even the implied warranty of
012: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: // Lesser General Public License for more details.
014: //
015: // You should have received a copy of the GNU Lesser General Public
016: // License along with this library; if not, write to the Free Software
017: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: ////////////////////////////////////////////////////////////////////////////////
019: package com.puppycrawl.tools.checkstyle;
020:
021: import java.io.Reader;
022: import java.io.IOException;
023:
024: /**
025: * A Reader that reads from an underlying String array, assuming each
026: * array element corresponds to one line of text.
027: * <p>
028: * <strong>Note: This class is not thread safe, concurrent reads might produce
029: * unexpected results! </strong> Checkstyle only works with one thread so
030: * currently there is no need to introduce synchronization here.
031: * </p>
032: * @author <a href="mailto:lkuehne@users.sourceforge.net">Lars Kühne</a>
033: */
034: final class StringArrayReader extends Reader {
035: /** the underlying String array */
036: private final String[] mUnderlyingArray;
037:
038: /** array containing the length of the strings. */
039: private final int[] mLenghtArray;
040:
041: /** the index of the currently read String */
042: private int mArrayIdx;
043:
044: /** the index of the next character to be read */
045: private int mStringIdx;
046:
047: /** flag to tell whether an implicit newline has to be reported */
048: private boolean mUnreportedNewline;
049:
050: /** flag to tell if the reader has been closed */
051: private boolean mClosed;
052:
053: /**
054: * Creates a new StringArrayReader.
055: *
056: * @param aUnderlyingArray the underlying String array.
057: */
058: StringArrayReader(String[] aUnderlyingArray) {
059: final int length = aUnderlyingArray.length;
060: mUnderlyingArray = new String[length];
061: System.arraycopy(aUnderlyingArray, 0, mUnderlyingArray, 0,
062: length);
063:
064: //additionally store the length of the strings
065: //for performance optimization
066: mLenghtArray = new int[length];
067: for (int i = 0; i < length; i++) {
068: mLenghtArray[i] = mUnderlyingArray[i].length();
069: }
070: }
071:
072: /** @see Reader */
073: public void close() {
074: mClosed = true;
075: }
076:
077: /** @return whether data is available that has not yet been read. */
078: private boolean dataAvailable() {
079: return (mUnderlyingArray.length > mArrayIdx);
080: }
081:
082: /** {@inheritDoc} */
083: public int read(char[] aCbuf, int aOff, int aLen)
084: throws IOException {
085: ensureOpen();
086:
087: int retVal = 0;
088:
089: if (!mUnreportedNewline
090: && (mUnderlyingArray.length <= mArrayIdx)) {
091: return -1;
092: }
093:
094: while ((retVal < aLen)
095: && (mUnreportedNewline || dataAvailable())) {
096: if (mUnreportedNewline) {
097: aCbuf[aOff + retVal] = '\n';
098: retVal++;
099: mUnreportedNewline = false;
100: }
101:
102: if ((retVal < aLen) && dataAvailable()) {
103: final String currentStr = mUnderlyingArray[mArrayIdx];
104: final int currentLenth = mLenghtArray[mArrayIdx];
105: final int srcEnd = Math.min(currentLenth, mStringIdx
106: + aLen - retVal);
107: currentStr.getChars(mStringIdx, srcEnd, aCbuf, aOff
108: + retVal);
109: retVal += srcEnd - mStringIdx;
110: mStringIdx = srcEnd;
111:
112: if (mStringIdx >= currentLenth) {
113: mArrayIdx++;
114: mStringIdx = 0;
115: mUnreportedNewline = true;
116: }
117: }
118: }
119: return retVal;
120: }
121:
122: /** {@inheritDoc} */
123: public int read() throws IOException {
124: if (mUnreportedNewline) {
125: mUnreportedNewline = false;
126: return '\n';
127: }
128:
129: if ((mArrayIdx < mUnderlyingArray.length)
130: && (mStringIdx < mLenghtArray[mArrayIdx])) {
131: // this is the common case,
132: // avoid char[] creation in super.read for performance
133: ensureOpen();
134: return mUnderlyingArray[mArrayIdx].charAt(mStringIdx++);
135: }
136: // don't bother duplicating the new line handling above
137: // for the uncommon case
138: return super .read();
139: }
140:
141: /**
142: * Throws an IOException if the reader has already been closed.
143: *
144: * @throws IOException if the stream has been closed
145: */
146: private void ensureOpen() throws IOException {
147: if (mClosed) {
148: throw new IOException("already closed");
149: }
150: }
151: }
|