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

org.opentcs.util.Streams Maven / Gradle / Ivy

There is a newer version: 6.2.0
Show newest version
/**
 * Copyright (c) The openTCS Authors.
 *
 * This program is free software and subject to the MIT license. (For details,
 * see the licensing information (LICENSE.txt) you should have received with
 * this copy of the software.)
 */
package org.opentcs.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import static java.util.Objects.requireNonNull;
import static org.opentcs.util.Assertions.checkInRange;

/**
 * This class provides helper methods for working with streams.
 *
 * @author Stefan Walter (Fraunhofer IML)
 */
public final class Streams {

  /**
   * The initial size for a growing buffer.
   */
  private static final int INITIAL_BUFFER_SIZE = 10000;

  /**
   * Creates a new Streams.
   */
  private Streams() {
  }

  /**
   * Reads an InputStream until it recognizes a given end tag, and
   * returns a new InputStream containing only the bytes up to and
   * including that end tag.
   *
   * @param inStream The stream to read from.
   * @param endTag The sequence of bytes marking the end of the content to be
   * returned.
   * @param includeEndTag Whether or not to include the end tag in the result.
   * @return A new InputStream, containing only the bytes up to and
   * including the end tag, or null, if the end of the stream was
   * reached and no such tag was found. (The bytes read from the stream are
   * discarded.)
   * @throws IOException If an I/O error occurs while reading from the input
   * stream.
   */
  public static InputStream getInputStreamToEndTag(InputStream inStream,
                                                   byte[] endTag,
                                                   boolean includeEndTag)
      throws IOException {
    requireNonNull(inStream, "inStream");
    requireNonNull(endTag, "endTag");
    checkInRange(endTag.length, 1, Integer.MAX_VALUE, "endTag.length");

    SearchableByteArrayOutputStream localBuffer = new SearchableByteArrayOutputStream();
    boolean endTagFound = false;
    int currentByte = inStream.read();
    while (!endTagFound && currentByte != -1) {
      localBuffer.write(currentByte);
      endTagFound = localBuffer.endsWith(endTag);
      currentByte = inStream.read();
    }

    if (endTagFound) {
      ByteArrayInputStream result;
      byte[] input = localBuffer.toByteArray();

      if (includeEndTag) {
        result = new ByteArrayInputStream(input);
      }
      else {
        result = new ByteArrayInputStream(input, 0, input.length - endTag.length);
      }

      return result;
    }
    else {
      return null;
    }
  }

  /**
   * Reads an InputStream to the end and returns an array
   * containing all bytes read.
   * The given InputStream will be closed when this method returns.
   *
   * @param inStream The stream to read from.
   * @return An array containing all bytes read from the given
   * InputStream. If nothing was read, the returned array's length
   * will be 0.
   * @throws IOException If an I/O error occurs while reading from the input
   * stream.
   */
  public static byte[] getCompleteInputStream(InputStream inStream)
      throws IOException {
    requireNonNull(inStream, "inStream");

    int bufferSize = INITIAL_BUFFER_SIZE;
    int offset = 0;
    byte[] buffer = new byte[bufferSize];

    try {
      int bytesRead = inStream.read(buffer, offset, bufferSize - offset);

      while (bytesRead != -1) {
        offset += bytesRead;
        // Enlarge the buffer if it's full.
        if (offset == bufferSize) {
          bufferSize *= 2;
          buffer = Arrays.copyOf(buffer, bufferSize);
        }

        bytesRead = inStream.read(buffer, offset, bufferSize - offset);
      }
    }
    finally {
      inStream.close();
    }
    // Shrink the buffer to the actual size of the data read.
    if (offset < bufferSize) {
      buffer = Arrays.copyOf(buffer, offset);
    }

    return buffer;
  }

  /**
   * A {@code ByteArrayOutputStream} providing additional methods to scan its
   * content for byte sequences.
   */
  private static class SearchableByteArrayOutputStream
      extends ByteArrayOutputStream {

    /**
     * Creates a new SearchableByteArrayOutputStream.
     */
    public SearchableByteArrayOutputStream() {
    }

    /**
     * Checks if this stream currently ends with the given byte sequence.
     *
     * @param endTag The byte sequence to check for.
     * @return {@code true} if, and only if, this stream currently ends with the
     * given byte sequence.
     */
    public boolean endsWith(byte[] endTag) {
      boolean result = false;

      if (count >= endTag.length) {
        result = true;

        for (int i = 1; i <= endTag.length; i++) {
          if (endTag[endTag.length - i] != buf[count - i]) {
            result = false;
            break;
          }
        }
      }

      return result;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy