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 */
017package org.apache.juneau.internal;
018
019import java.io.*;
020
021/**
022 * Similar to {@link StringReader} except reads from a generic {@link CharSequenceReader}.
023 *
024 * <h5 class='section'>See Also:</h5><ul>
025
026 * </ul>
027 */
028public class CharSequenceReader extends BufferedReader {
029
030   private final CharSequence cs;
031   private String s;
032   private StringBuffer sb;
033   private StringBuilder sb2;
034   private int length;
035   private int next;
036
037   /**
038    * Constructor.
039    *
040    * @param cs The char sequence to read from.  Can be <jk>null</jk>.
041    */
042   public CharSequenceReader(CharSequence cs) {
043      super(new StringReader(""), 1);   // Does not actually use a reader.
044      if (cs == null)
045         cs = "";
046      this.cs = cs;
047      if (cs instanceof String)
048         s = (String)cs;
049      else if (cs instanceof StringBuffer)
050         sb = (StringBuffer)cs;
051      else if (cs instanceof StringBuilder)
052         sb2 = (StringBuilder)cs;
053      this.length = cs.length();
054   }
055
056   @Override /* Reader */
057   public int read() {
058      if (next >= length)
059         return -1;
060      return cs.charAt(next++);
061   }
062
063   @Override /* Reader */
064   public boolean markSupported() {
065      return false;
066   }
067
068   @Override /* Reader */
069   public int read(final char[] cbuf, final int off, final int len) {
070      if (next >= length)
071         return -1;
072      int n = Math.min(length - next, len);
073      if (s != null)
074         s.getChars(next, next + n, cbuf, off);
075      else if (sb != null)
076         sb.getChars(next, next + n, cbuf, off);
077      else if (sb2 != null)
078         sb2.getChars(next, next + n, cbuf, off);
079      else {
080         for (int i = 0; i < n; i++)
081            cbuf[off+i] = cs.charAt(next+i);
082      }
083      next += n;
084      return n;
085   }
086
087   @Override /* Reader */
088   public long skip(long ns) {
089      if (next >= length)
090         return 0;
091      long n = Math.min(length - next, ns);
092      n = Math.max(-next, n);
093      next += n;
094      return n;
095   }
096
097   @Override /* Reader */
098   public void close() {
099      // no-op
100   }
101
102   @Override /* Object */
103   public String toString() {
104      return cs.toString();
105   }
106}