All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.mmm.crypto.crypt.CryptorInputStream Maven / Gradle / Ivy

package io.github.mmm.crypto.crypt;

import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;

import io.github.mmm.crypto.io.InputStreamWrapper;
import io.github.mmm.crypto.io.OutputStreamWrapper;

/**
 * Implementation of {@link InputStream} for {@link Decryptor#wrapStream(InputStream)} based on
 * {@link OutputStreamWrapper}.
 *
 * @author Joerg Hohwiller (hohwille at users.sourceforge.net)
 * @since 1.0.0
 */
public class CryptorInputStream extends InputStreamWrapper {

  private Cryptor cryptor;

  private final byte[] inBuffer;

  private byte[] outBuffer;

  private int outStart;

  private int outEnd;

  private boolean done; // delegate stream has been consumed?

  /**
   * The constructor.
   *
   * @param cryptor the {@link Cryptor}.
   * @param delegate the {@link InputStream} to wrap.
   */
  public CryptorInputStream(Cryptor cryptor, InputStream delegate) {
    super(delegate);
    Objects.requireNonNull(cryptor, "cryptor");
    this.cryptor = cryptor;
    this.inBuffer = new byte[512];
    this.outBuffer = null;
    this.outStart = 0;
    this.done = false;
  }

  private int fillBuffer() throws IOException {

    if (this.done) {
      return -1;
    }

    int bytesRead = 0;
    while (bytesRead == 0) {
      bytesRead = getDelegate().read(this.inBuffer);
    }
    if (bytesRead == -1) {
      this.done = true;
      this.outBuffer = this.cryptor.doFinal();
      if ((this.outBuffer == null) || (this.outBuffer.length == 0)) {
        return -1;
      }
    } else {
      this.outBuffer = this.cryptor.crypt(this.inBuffer, 0, bytesRead, false);
    }
    this.outStart = 0;
    this.outEnd = this.outBuffer.length;
    return this.outEnd;
  }

  private boolean hasData() throws IOException {

    if (this.outStart < this.outEnd) {
      return true;
    }
    int bytesRead = 0;
    while (bytesRead == 0) {
      bytesRead = fillBuffer();
    }
    return (bytesRead > 0);
  }

  @Override
  public int read(byte[] b, int off, int len) throws IOException {

    requireNotClosed();
    if (!hasData()) {
      return -1;
    }
    if ((len <= 0) || (b == null)) {
      return 0;
    }
    int available = this.outEnd - this.outStart;
    if (len < available) {
      available = len;
    }
    System.arraycopy(this.outBuffer, this.outStart, b, off, available);
    this.outStart += available;
    return available;
  }

  @Override
  public int read() throws IOException {

    requireNotClosed();
    if (!hasData()) {
      return -1;
    }
    int result = this.outBuffer[this.outStart++];
    return result & 0xff;
  }

  @Override
  public long skip(long n) throws IOException {

    int skip = this.outEnd - this.outStart;
    if (skip > n) {
      skip = (int) n;
    }
    this.outStart += skip;
    return skip;
  }

  @Override
  public int available() throws IOException {

    return (this.outEnd - this.outStart);
  }

  @Override
  public void close() throws IOException {

    super.close();
    if (this.cryptor != null) {
      try {
        this.cryptor.doFinal();
      } catch (Exception e) {
        // ignore...
      }
    }
    this.cryptor = null;
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy