ZstdCompressorInputStream.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one
  3.  * or more contributor license agreements.  See the NOTICE file
  4.  * distributed with this work for additional information
  5.  * regarding copyright ownership.  The ASF licenses this file
  6.  * to you under the Apache License, Version 2.0 (the
  7.  * "License"); you may not use this file except in compliance
  8.  * with the License.  You may obtain a copy of the License at
  9.  *
  10.  *   https://www.apache.org/licenses/LICENSE-2.0
  11.  *
  12.  * Unless required by applicable law or agreed to in writing,
  13.  * software distributed under the License is distributed on an
  14.  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15.  * KIND, either express or implied.  See the License for the
  16.  * specific language governing permissions and limitations
  17.  * under the License.
  18.  */

  19. package org.apache.commons.compress.compressors.zstandard;

  20. import java.io.IOException;
  21. import java.io.InputStream;

  22. import org.apache.commons.compress.compressors.CompressorInputStream;
  23. import org.apache.commons.compress.utils.InputStreamStatistics;
  24. import org.apache.commons.io.input.BoundedInputStream;

  25. import com.github.luben.zstd.BufferPool;
  26. import com.github.luben.zstd.ZstdInputStream;

  27. /**
  28.  * {@link CompressorInputStream} implementation to decode Zstandard encoded stream.
  29.  *
  30.  * <p>
  31.  * This class avoids making the underlying {@code zstd} classes part of the public or protected API. The underlying implementation is provided through the
  32.  * <a href="https://github.com/luben/zstd-jni/">Zstandard JNI</a> library which is based on <a href="https://github.com/facebook/zstd/">zstd</a>.
  33.  * </p>
  34.  *
  35.  * @see <a href="https://github.com/luben/zstd-jni/">Zstandard JNI</a>
  36.  * @see <a href="https://github.com/facebook/zstd/">zstd</a>
  37.  * @since 1.16
  38.  */
  39. public class ZstdCompressorInputStream extends CompressorInputStream implements InputStreamStatistics {

  40.     private final BoundedInputStream countingStream;
  41.     private final ZstdInputStream decIS;

  42.     /**
  43.      * Constructs a new input stream that decompresses zstd-compressed data from the specific input stream.
  44.      *
  45.      * @param in         the input stream of compressed data.
  46.      * @throws IOException if an I/O error occurs.
  47.      */
  48.     public ZstdCompressorInputStream(final InputStream in) throws IOException {
  49.         this.decIS = new ZstdInputStream(countingStream = BoundedInputStream.builder().setInputStream(in).get());
  50.     }

  51.     /**
  52.      * Constructs a new input stream that decompresses zstd-compressed data from the specific input stream.
  53.      *
  54.      * @param in         the input stream of compressed data.
  55.      * @param bufferPool a configuration of zstd-jni that allows users to customize how buffers are recycled. Either a {@link com.github.luben.zstd.NoPool} or a
  56.      *                   {@link com.github.luben.zstd.RecyclingBufferPool} is allowed here.
  57.      * @throws IOException if an I/O error occurs.
  58.      */
  59.     public ZstdCompressorInputStream(final InputStream in, final BufferPool bufferPool) throws IOException {
  60.         this.decIS = new ZstdInputStream(countingStream = BoundedInputStream.builder().setInputStream(in).get(), bufferPool);
  61.     }

  62.     @Override
  63.     public int available() throws IOException {
  64.         return decIS.available();
  65.     }

  66.     @Override
  67.     public void close() throws IOException {
  68.         decIS.close();
  69.     }

  70.     /**
  71.      *
  72.      * {@inheritDoc}
  73.      *
  74.      * @since 1.17
  75.      */
  76.     @Override
  77.     public long getCompressedCount() {
  78.         return countingStream.getCount();
  79.     }

  80.     @Override
  81.     public synchronized void mark(final int readLimit) {
  82.         decIS.mark(readLimit);
  83.     }

  84.     @Override
  85.     public boolean markSupported() {
  86.         return decIS.markSupported();
  87.     }

  88.     @Override
  89.     public int read() throws IOException {
  90.         final int ret = decIS.read();
  91.         count(ret == -1 ? 0 : 1);
  92.         return ret;
  93.     }

  94.     @Override
  95.     public int read(final byte[] b) throws IOException {
  96.         return read(b, 0, b.length);
  97.     }

  98.     @Override
  99.     public int read(final byte[] buf, final int off, final int len) throws IOException {
  100.         if (len == 0) {
  101.             return 0;
  102.         }
  103.         final int ret = decIS.read(buf, off, len);
  104.         count(ret);
  105.         return ret;
  106.     }

  107.     @Override
  108.     public synchronized void reset() throws IOException {
  109.         decIS.reset();
  110.     }

  111.     @Override
  112.     public long skip(final long n) throws IOException {
  113.         return org.apache.commons.io.IOUtils.skip(decIS, n);
  114.     }

  115.     @Override
  116.     public String toString() {
  117.         return decIS.toString();
  118.     }
  119. }