content: /*
   * Copyright (C) 2010 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.util;
  
  import java.io.FilterInputStream;
  import java.io.IOException;
  import java.io.InputStream;
  
  /**
   * An InputStream that does Base64 decoding on the data read through
   * it.
   */
  public class Base64InputStream extends FilterInputStream {
      private final Base64.Coder coder;
  
      private static byte[] EMPTY = new byte[0];
  
      private static final int BUFFER_SIZE = 2048;
      private boolean eof;
      private byte[] inputBuffer;
      private int outputStart;
      private int outputEnd;
  
      /**
       * An InputStream that performs Base64 decoding on the data read
       * from the wrapped stream.
       *
       * @param in the InputStream to read the source data from
       * @param flags bit flags for controlling the decoder; see the
       *        constants in {@link Base64}
       */
      public Base64InputStream(InputStream in, int flags) {
          this(in, flags, false);
      }
  
      /**
       * Performs Base64 encoding or decoding on the data read from the
       * wrapped InputStream.
       *
       * @param in the InputStream to read the source data from
       * @param flags bit flags for controlling the decoder; see the
       *        constants in {@link Base64}
       * @param encode true to encode, false to decode
       *
       * @hide
       */
      public Base64InputStream(InputStream in, int flags, boolean encode) {
          super(in);
          eof = false;
          inputBuffer = new byte[BUFFER_SIZE];
          if (encode) {
              coder = new Base64.Encoder(flags, null);
          } else {
              coder = new Base64.Decoder(flags, null);
          }
          coder.output = new byte[coder.maxOutputSize(BUFFER_SIZE)];
          outputStart = 0;
          outputEnd = 0;
      }
  
      public boolean markSupported() {
          return false;
      }
  
      public void mark(int readlimit) {
          throw new UnsupportedOperationException();
      }
  
      public void reset() {
          throw new UnsupportedOperationException();
      }
  
      public void close() throws IOException {
          in.close();
          inputBuffer = null;
      }
  
      public int available() {
          return outputEnd - outputStart;
      }
  
      public long skip(long n) throws IOException {
          if (outputStart >= outputEnd) {
              refill();
          }
          if (outputStart >= outputEnd) {
              return 0;
          }
          long bytes = Math.min(n, outputEnd-outputStart);
          outputStart += bytes;
          return bytes;
      }
  
      public int read() throws IOException {
          if (outputStart >= outputEnd) {
              refill();
          }
          if (outputStart >= outputEnd) {
              return -1;
          } else {
              return coder.output[outputStart++] & 0xff;
          }
      }
  
      public int read(byte[] b, int off, int len) throws IOException {
          if (outputStart >= outputEnd) {
              refill();
          }
          if (outputStart >= outputEnd) {
              return -1;
          }
          int bytes = Math.min(len, outputEnd-outputStart);
          System.arraycopy(coder.output, outputStart, b, off, bytes);
          outputStart += bytes;
          return bytes;
      }
  
      /**
       * Read data from the input stream into inputBuffer, then
       * decode/encode it into the empty coder.output, and reset the
       * outputStart and outputEnd pointers.
       */
      private void refill() throws IOException {
          if (eof) return;
          int bytesRead = in.read(inputBuffer);
          boolean success;
          if (bytesRead == -1) {
              eof = true;
              success = coder.process(EMPTY, 0, 0, true);
          } else {
              success = coder.process(inputBuffer, 0, bytesRead, false);
          }
          if (!success) {
              throw new Base64DataException("bad base-64");
          }
          outputEnd = coder.op;
          outputStart = 0;
      }
  }
  