/* * * 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(); } }