001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2009 SonarSource SA
004     * mailto:contact AT sonarsource DOT com
005     *
006     * Sonar is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 3 of the License, or (at your option) any later version.
010     *
011     * Sonar is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public
017     * License along with Sonar; if not, write to the Free Software
018     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
019     */
020    package org.sonar.squid.text;
021    
022    import java.io.IOException;
023    import java.io.Reader;
024    
025    public class StringArrayReader extends Reader {
026    
027      private String[] array;
028      private int rowIndex = 0;
029      private int rowIndexMark = 0;
030      private int colIndex = 0;
031      private int colIndexMark = 0;
032      private static final char END_OF_LINE_CHAR = '\n';
033      private boolean ready = true;
034    
035      public StringArrayReader(String array[]) {
036        this.array = array;
037      }
038    
039      @Override
040      public void close() throws IOException {
041        array = null;
042        ready = false;
043      }
044    
045      @Override
046      public boolean ready() throws IOException {
047        return ready;
048      }
049    
050      @Override
051      public boolean markSupported() {
052        return true;
053      }
054    
055      @Override
056      public void mark(int readAheadLimit) throws IOException {
057        rowIndexMark = rowIndex;
058        colIndexMark = colIndex;
059      }
060    
061      @Override
062      public void reset() throws IOException {
063        rowIndex = rowIndexMark;
064        colIndex = colIndexMark;
065      }
066    
067      @Override
068      public int read(char[] cbuf, int off, int len) throws IOException {
069        if (isEndOfArray()) {
070          return -1;
071        }
072        if (isEndOfCurrentLine()) {
073          switchToNewLine(cbuf, off);
074          if (len > 1) {
075            int numberOfReadChars = 1 + read(cbuf, off + 1, len - 1);
076            return (numberOfReadChars == 0 ? 1 : numberOfReadChars);
077          } else {
078            return 1;
079          }
080        }
081        if (isThereEnoughCharsOnCurrentLine(len)) {
082          getCurrentLine().getChars(colIndex, colIndex + len, cbuf, off);
083          colIndex += len;
084          return len;
085        } else {
086          getCurrentLine().getChars(colIndex, getCurrentLine().length(), cbuf, off);
087          int readLength = getCurrentLine().length() - colIndex;
088          colIndex = getCurrentLine().length();
089          int nextReadLength = read(cbuf, off + readLength, len - readLength);
090          return readLength + (nextReadLength > -1 ? nextReadLength : 0);
091        }
092      }
093    
094      private boolean isThereEnoughCharsOnCurrentLine(int len) {
095        return colIndex + len <= getCurrentLine().length();
096      }
097    
098      private boolean isEndOfArray() {
099        return array == null || array.length == 0 || (isEndOfCurrentLine() && rowIndex == array.length - 1);
100      }
101    
102      private boolean isEndOfCurrentLine() {
103        return colIndex >= getCurrentLine().length();
104      }
105    
106      private String getCurrentLine() {
107        return array[rowIndex];
108      }
109    
110      private void switchToNewLine(char[] cbuf, int off) {
111        cbuf[off] = END_OF_LINE_CHAR;
112        colIndex = 0;
113        rowIndex++;
114      }
115    
116    }