001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 020package org.apache.commons.compress.compressors.zstandard; 021 022import java.io.IOException; 023import java.io.InputStream; 024 025import org.apache.commons.compress.compressors.CompressorInputStream; 026import org.apache.commons.compress.utils.InputStreamStatistics; 027import org.apache.commons.io.input.BoundedInputStream; 028 029import com.github.luben.zstd.BufferPool; 030import com.github.luben.zstd.ZstdInputStream; 031 032/** 033 * {@link CompressorInputStream} implementation to decode Zstandard encoded stream. 034 * 035 * <p> 036 * This class avoids making the underlying {@code zstd} classes part of the public or protected API. The underlying implementation is provided through the 037 * <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>. 038 * </p> 039 * 040 * @see <a href="https://github.com/luben/zstd-jni/">Zstandard JNI</a> 041 * @see <a href="https://github.com/facebook/zstd/">zstd</a> 042 * @since 1.16 043 */ 044public class ZstdCompressorInputStream extends CompressorInputStream implements InputStreamStatistics { 045 046 private final BoundedInputStream countingStream; 047 private final ZstdInputStream decIS; 048 049 /** 050 * Constructs a new input stream that decompresses zstd-compressed data from the specific input stream. 051 * 052 * @param in the input stream of compressed data. 053 * @throws IOException if an I/O error occurs. 054 */ 055 public ZstdCompressorInputStream(final InputStream in) throws IOException { 056 this.decIS = new ZstdInputStream(countingStream = BoundedInputStream.builder().setInputStream(in).get()); 057 } 058 059 /** 060 * Constructs a new input stream that decompresses zstd-compressed data from the specific input stream. 061 * 062 * @param in the input stream of compressed data. 063 * @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 064 * {@link com.github.luben.zstd.RecyclingBufferPool} is allowed here. 065 * @throws IOException if an I/O error occurs. 066 */ 067 public ZstdCompressorInputStream(final InputStream in, final BufferPool bufferPool) throws IOException { 068 this.decIS = new ZstdInputStream(countingStream = BoundedInputStream.builder().setInputStream(in).get(), bufferPool); 069 } 070 071 @Override 072 public int available() throws IOException { 073 return decIS.available(); 074 } 075 076 @Override 077 public void close() throws IOException { 078 decIS.close(); 079 } 080 081 /** 082 * 083 * {@inheritDoc} 084 * 085 * @since 1.17 086 */ 087 @Override 088 public long getCompressedCount() { 089 return countingStream.getCount(); 090 } 091 092 @Override 093 public synchronized void mark(final int readLimit) { 094 decIS.mark(readLimit); 095 } 096 097 @Override 098 public boolean markSupported() { 099 return decIS.markSupported(); 100 } 101 102 @Override 103 public int read() throws IOException { 104 final int ret = decIS.read(); 105 count(ret == -1 ? 0 : 1); 106 return ret; 107 } 108 109 @Override 110 public int read(final byte[] b) throws IOException { 111 return read(b, 0, b.length); 112 } 113 114 @Override 115 public int read(final byte[] buf, final int off, final int len) throws IOException { 116 if (len == 0) { 117 return 0; 118 } 119 final int ret = decIS.read(buf, off, len); 120 count(ret); 121 return ret; 122 } 123 124 @Override 125 public synchronized void reset() throws IOException { 126 decIS.reset(); 127 } 128 129 @Override 130 public long skip(final long n) throws IOException { 131 return org.apache.commons.io.IOUtils.skip(decIS, n); 132 } 133 134 @Override 135 public String toString() { 136 return decIS.toString(); 137 } 138}