View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *  http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  package org.apache.any23.util;
    19
    20  import java.io.IOException;
    21  import java.io.InputStream;
    22  import java.io.Reader;
    23
    24  /**
    25   * Adapts a <code>Reader</code> as an <code>InputStream</code>. Adapted from <CODE>StringInputStream</CODE>.
    26   *
    27   */
    28  public class ReaderInputStream extends InputStream {
    29
    30      /** Source Reader */
    31      private Reader in;
    32
    33      private String encoding = System.getProperty("file.encoding");
    34
    35      private byte[] slack;
    36
    37      private int begin;
    38
    39      /**
    40       * Construct a <CODE>ReaderInputStream</CODE> for the specified <CODE>Reader</CODE>.
    41       *
    42       * @param reader
    43       *            <CODE>Reader</CODE>. Must not be <code>null</code>.
    44       */
    45      public ReaderInputStream(Reader reader) {
    46          in = reader;
    47      }
    48
    49      /**
    50       * Construct a <CODE>ReaderInputStream</CODE> for the specified <CODE>Reader</CODE>, with the specified encoding.
    51       *
    52       * @param reader
    53       *            non-null <CODE>Reader</CODE>.
    54       * @param encoding
    55       *            non-null <CODE>String</CODE> encoding.
    56       */
    57      public ReaderInputStream(Reader reader, String encoding) {
    58          this(reader);
    59          if (encoding == null) {
    60              throw new IllegalArgumentException("encoding must not be null");
    61          } else {
    62              this.encoding = encoding;
    63          }
    64      }
    65
    66      /**
    67       * Reads from the <CODE>Reader</CODE>, returning the same value.
    68       *
    69       * @return the value of the next character in the <CODE>Reader</CODE>.
    70       *
    71       * @exception IOException
    72       *                if the original <code>Reader</code> fails to be read
    73       */
    74      public synchronized int read() throws IOException {
    75          if (in == null) {
    76              throw new IOException("Stream Closed");
    77          }
    78
    79          byte result;
    80          if (slack != null && begin < slack.length) {
    81              result = slack[begin];
    82              if (++begin == slack.length) {
    83                  slack = null;
    84              }
    85          } else {
    86              byte[] buf = new byte[1];
    87              if (read(buf, 0, 1) <= 0) {
    88                  result = -1;
    89              }
    90              result = buf[0];
    91          }
    92
    93          if (result < -1) {
    94              result += 256;
    95          }
    96
    97          return result;
    98      }
    99
    100     /**
    101      * Reads from the <code>Reader</code> into a byte array
    102      *
    103      * @param b
    104      *            the byte array to read into
    105      * @param off
    106      *            the offset in the byte array
    107      * @param len
    108      *            the length in the byte array to fill
    109      *
    110      * @return the actual number read into the byte array, -1 at the end of the stream
    111      *
    112      * @exception IOException
    113      *                if an error occurs
    114      */
    115     public synchronized int read(byte[] b, int off, int len) throws IOException {
    116         if (in == null) {
    117             throw new IOException("Stream Closed");
    118         }
    119
    120         while (slack == null) {
    121             char[] buf = new char[len]; // might read too much
    122             int n = in.read(buf);
    123             if (n == -1) {
    124                 return -1;
    125             }
    126             if (n > 0) {
    127                 slack = new String(buf, 0, n).getBytes(encoding);
    128                 begin = 0;
    129             }
    130         }
    131
    132         if (len > slack.length - begin) {
    133             len = slack.length - begin;
    134         }
    135
    136         System.arraycopy(slack, begin, b, off, len);
    137
    138         if ((begin += len) >= slack.length) {
    139             slack = null;
    140         }
    141
    142         return len;
    143     }
    144
    145     /**
    146      * Marks the read limit of the StringReader.
    147      *
    148      * @param limit
    149      *            the maximum limit of bytes that can be read before the mark position becomes invalid
    150      */
    151     public synchronized void mark(final int limit) {
    152         try {
    153             in.mark(limit);
    154         } catch (IOException ioe) {
    155             throw new RuntimeException(ioe.getMessage());
    156         }
    157     }
    158
    159     /**
    160      * @return the current number of bytes ready for reading
    161      *
    162      * @exception IOException
    163      *                if an error occurs
    164      */
    165     public synchronized int available() throws IOException {
    166         if (in == null) {
    167             throw new IOException("Stream Closed");
    168         }
    169         if (slack != null) {
    170             return slack.length - begin;
    171         }
    172         if (in.ready()) {
    173             return 1;
    174         } else {
    175             return 0;
    176         }
    177     }
    178
    179     /**
    180      * @return false - mark is not supported
    181      */
    182     public boolean markSupported() {
    183         return false; // would be imprecise
    184     }
    185
    186     /**
    187      * Resets the StringReader.
    188      *
    189      * @exception IOException
    190      *                if the StringReader fails to be reset
    191      */
    192     public synchronized void reset() throws IOException {
    193         if (in == null) {
    194             throw new IOException("Stream Closed");
    195         }
    196         slack = null;
    197         in.reset();
    198     }
    199
    200     /**
    201      * Closes the Stringreader.
    202      *
    203      * @exception IOException
    204      *                if the original StringReader fails to be closed
    205      */
    206     public synchronized void close() throws IOException {
    207         if (in != null) {
    208             in.close();
    209             slack = null;
    210             in = null;
    211         }
    212     }
    213 }