| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| package org.apache.flex.swf.io; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| |
| import org.apache.flex.utils.DAByteArrayOutputStream; |
| |
| import SevenZip.Compression.LZMA.Encoder; |
| |
| public class LZMACompressor |
| { |
| public LZMACompressor() |
| { |
| // init the encoder to it is ready for work |
| encoder = new Encoder(); |
| |
| // Note: algorithm doesn't do anything at this time. |
| /// value 1 is supposed to be "max" |
| if (!encoder.SetAlgorithm(1)) |
| assert false; |
| |
| // Dictionary size |
| // This is the default value from the 7Zip example (1 << 21) |
| // It is not obvious that making it bigger will give better results. Be aware that the |
| // implementation seems to allocate 2X ints, so 8Xbytes. |
| int dictionarySize = 1 << 21; |
| if (!encoder.SetDictionarySize(dictionarySize)) |
| assert false; |
| |
| // set number of fast bytes - [5, 273], default: 128\n" + |
| if (!encoder.SetNumFastBytes(128)) |
| assert false; |
| |
| // -mf{MF_ID}: set Match Finder: [bt2, bt4], default: bt4\n" + |
| if (!encoder.SetMatchFinder(1)) |
| assert false; |
| |
| //" -lc{N}: set number of literal context bits - [0, 8], default: 3\n" + |
| //" -lp{N}: set number of literal pos bits - [0, 4], default: 0\n" + |
| //" -pb{N}: set number of pos bits - [0, 4], default: 2\n" + |
| int lc = 3; |
| int lp = 0; |
| int pb = 2; |
| |
| if (!encoder.SetLcLpPb(lc, lp, pb)) |
| assert false; |
| |
| // set marker mode to true, so that we write out |
| // an explicit "end of stream" marker, as per the |
| // SFW LZMA spec |
| encoder.SetEndMarkerMode(true); |
| } |
| |
| // We will compress all of our data into this data structure, |
| // so that we can easily stream it out later |
| private DAByteArrayOutputStream byteArrayOutputStream = null; |
| |
| private final Encoder encoder; |
| |
| /** |
| * This simple wrapper make an IOutputBitStream look like in InputSteam. |
| * LZMA library needs an Input stream, but our SWF infrastructure is already |
| * using IOutputBitStream. |
| */ |
| public static class StreamAdapter extends InputStream |
| { |
| public StreamAdapter(IOutputBitStream outputBitStream) |
| { |
| // Fetch the raw bytes from outputBitStream, and |
| // save them so we can serve them up later |
| bytes = outputBitStream.getBytes(); |
| totalByteCount = outputBitStream.size(); |
| } |
| |
| private final byte[] bytes; |
| private final long totalByteCount; |
| private int position = 0; |
| |
| /** |
| * Implemeint InputStream.read() |
| */ |
| @Override |
| public int read() throws IOException |
| { |
| int ret = -1; |
| if (position >= totalByteCount) |
| ret = -1; |
| else |
| { |
| ret = bytes[position++]; |
| if (ret < 0) |
| ret += 256; // Java signed byte -> unsigned |
| } |
| return ret; |
| } |
| |
| /** |
| * @return the number of bytes in the input stream |
| */ |
| long getCount() |
| { |
| return totalByteCount; |
| } |
| } |
| |
| /** |
| * Compresses all of the data in outputBitStream into |
| * this.byteArrayOutputStream Must be called before any of the write |
| * methods. |
| */ |
| public void compress(IOutputBitStream outputBitStream) throws IOException |
| { |
| assert byteArrayOutputStream == null; |
| byteArrayOutputStream = new DAByteArrayOutputStream(); |
| StreamAdapter is = new StreamAdapter(outputBitStream); |
| encoder.Code(is, byteArrayOutputStream, -1, -1, null); |
| } |
| |
| /** |
| * Write the LZMA compression properties to the output. These are part the |
| * the SWF header |
| * |
| * @param outputStream The output stream. |
| */ |
| public void writeLZMAProperties(OutputStream outputStream) throws IOException |
| { |
| encoder.WriteCoderProperties(outputStream); |
| } |
| |
| /** |
| * Write the actual compressed payload, and the EOS bytes at the end |
| */ |
| public void writeDataAndEnd(OutputStream outputStream) throws IOException |
| { |
| byte[] data = byteArrayOutputStream.getDirectByteArray(); |
| outputStream.write(data, 0, data.length); |
| outputStream.flush(); |
| } |
| |
| /** |
| * @return the length of the LZMA data, and the final EOS marker |
| */ |
| public long getLengthOfCompressedPayload() |
| { |
| assert byteArrayOutputStream != null; |
| return byteArrayOutputStream.size(); |
| } |
| |
| } |