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 */
019 package org.apache.commons.compress.compressors.xz;
020
021 import java.io.IOException;
022 import java.io.InputStream;
023 import org.tukaani.xz.XZ;
024 import org.tukaani.xz.SingleXZInputStream;
025 import org.tukaani.xz.XZInputStream;
026
027 import org.apache.commons.compress.compressors.CompressorInputStream;
028
029 /**
030 * XZ decompressor.
031 * @since Commons Compress 1.4
032 */
033 public class XZCompressorInputStream extends CompressorInputStream {
034 private final InputStream in;
035
036 /**
037 * Checks if the signature matches what is expected for a .xz file.
038 *
039 * @param signature the bytes to check
040 * @param length the number of bytes to check
041 * @return true if signature matches the .xz magic bytes, false otherwise
042 */
043 public static boolean matches(byte[] signature, int length) {
044 if (length < XZ.HEADER_MAGIC.length) {
045 return false;
046 }
047
048 for (int i = 0; i < XZ.HEADER_MAGIC.length; ++i) {
049 if (signature[i] != XZ.HEADER_MAGIC[i]) {
050 return false;
051 }
052 }
053
054 return true;
055 }
056
057 /**
058 * Creates a new input stream that decompresses XZ-compressed data
059 * from the specified input stream. This doesn't support
060 * concatenated .xz files.
061 *
062 * @param inputStream where to read the compressed data
063 *
064 * @throws IOException if the input is not in the .xz format,
065 * the input is corrupt or truncated, the .xz
066 * headers specify options that are not supported
067 * by this implementation, or the underlying
068 * <code>inputStream</code> throws an exception
069 */
070 public XZCompressorInputStream(InputStream inputStream)
071 throws IOException {
072 this(inputStream, false);
073 }
074
075 /**
076 * Creates a new input stream that decompresses XZ-compressed data
077 * from the specified input stream.
078 *
079 * @param inputStream where to read the compressed data
080 * @param decompressConcatenated
081 * if true, decompress until the end of the
082 * input; if false, stop after the first .xz
083 * stream and leave the input position to point
084 * to the next byte after the .xz stream
085 *
086 * @throws IOException if the input is not in the .xz format,
087 * the input is corrupt or truncated, the .xz
088 * headers specify options that are not supported
089 * by this implementation, or the underlying
090 * <code>inputStream</code> throws an exception
091 */
092 public XZCompressorInputStream(InputStream inputStream,
093 boolean decompressConcatenated)
094 throws IOException {
095 if (decompressConcatenated) {
096 in = new XZInputStream(inputStream);
097 } else {
098 in = new SingleXZInputStream(inputStream);
099 }
100 }
101
102 /** {@inheritDoc} */
103 @Override
104 public int read() throws IOException {
105 int ret = in.read();
106 count(ret == -1 ? -1 : 1);
107 return ret;
108 }
109
110 /** {@inheritDoc} */
111 @Override
112 public int read(byte[] buf, int off, int len) throws IOException {
113 int ret = in.read(buf, off, len);
114 count(ret);
115 return ret;
116 }
117
118 /** {@inheritDoc} */
119 @Override
120 public long skip(long n) throws IOException {
121 return in.skip(n);
122 }
123
124 /** {@inheritDoc} */
125 @Override
126 public int available() throws IOException {
127 return in.available();
128 }
129
130 /** {@inheritDoc} */
131 @Override
132 public void close() throws IOException {
133 in.close();
134 }
135 }