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 * http://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 */ 019package org.apache.commons.compress.compressors.lzma; 020 021import java.io.IOException; 022import java.io.InputStream; 023 024import org.apache.commons.compress.MemoryLimitException; 025import org.tukaani.xz.LZMAInputStream; 026 027import org.apache.commons.compress.compressors.CompressorInputStream; 028import org.apache.commons.compress.utils.CountingInputStream; 029import org.apache.commons.compress.utils.IOUtils; 030import org.apache.commons.compress.utils.InputStreamStatistics; 031 032/** 033 * LZMA decompressor. 034 * @since 1.6 035 */ 036public class LZMACompressorInputStream extends CompressorInputStream 037 implements InputStreamStatistics { 038 039 private final CountingInputStream countingStream; 040 private final InputStream in; 041 042 /** 043 * Creates a new input stream that decompresses LZMA-compressed data 044 * from the specified input stream. 045 * 046 * @param inputStream where to read the compressed data 047 * 048 * @throws IOException if the input is not in the .lzma format, 049 * the input is corrupt or truncated, the .lzma 050 * headers specify sizes that are not supported 051 * by this implementation, or the underlying 052 * <code>inputStream</code> throws an exception 053 */ 054 public LZMACompressorInputStream(final InputStream inputStream) 055 throws IOException { 056 in = new LZMAInputStream(countingStream = new CountingInputStream(inputStream), -1); 057 } 058 059 /** 060 * Creates a new input stream that decompresses LZMA-compressed data 061 * from the specified input stream. 062 * 063 * @param inputStream where to read the compressed data 064 * 065 * @param memoryLimitInKb calculated memory use threshold. Throws MemoryLimitException 066 * if calculate memory use is above this threshold 067 * 068 * @throws IOException if the input is not in the .lzma format, 069 * the input is corrupt or truncated, the .lzma 070 * headers specify sizes that are not supported 071 * by this implementation, or the underlying 072 * <code>inputStream</code> throws an exception 073 * 074 * @since 1.14 075 */ 076 public LZMACompressorInputStream(final InputStream inputStream, int memoryLimitInKb) 077 throws IOException { 078 try { 079 in = new LZMAInputStream(countingStream = new CountingInputStream(inputStream), memoryLimitInKb); 080 } catch (org.tukaani.xz.MemoryLimitException e) { 081 //convert to commons-compress exception 082 throw new MemoryLimitException(e.getMemoryNeeded(), e.getMemoryLimit(), e); 083 } 084 } 085 086 /** {@inheritDoc} */ 087 @Override 088 public int read() throws IOException { 089 final int ret = in.read(); 090 count(ret == -1 ? 0 : 1); 091 return ret; 092 } 093 094 /** {@inheritDoc} */ 095 @Override 096 public int read(final byte[] buf, final int off, final int len) throws IOException { 097 final int ret = in.read(buf, off, len); 098 count(ret); 099 return ret; 100 } 101 102 /** {@inheritDoc} */ 103 @Override 104 public long skip(final long n) throws IOException { 105 return IOUtils.skip(in, n); 106 } 107 108 /** {@inheritDoc} */ 109 @Override 110 public int available() throws IOException { 111 return in.available(); 112 } 113 114 /** {@inheritDoc} */ 115 @Override 116 public void close() throws IOException { 117 in.close(); 118 } 119 120 /** 121 * @since 1.17 122 */ 123 @Override 124 public long getCompressedCount() { 125 return countingStream.getBytesRead(); 126 } 127 128 /** 129 * Checks if the signature matches what is expected for an lzma file. 130 * 131 * @param signature 132 * the bytes to check 133 * @param length 134 * the number of bytes to check 135 * @return true, if this stream is an lzma compressed stream, false otherwise 136 * 137 * @since 1.10 138 */ 139 public static boolean matches(final byte[] signature, final int length) { 140 return signature != null && length >= 3 && 141 signature[0] == 0x5d && signature[1] == 0 && 142 signature[2] == 0; 143 } 144}