├── .travis.yml ├── src ├── test │ ├── resources │ │ ├── ajar.jar │ │ ├── doc.pdf │ │ ├── hello.txt.lzma │ │ └── plaintext.txt │ └── java │ │ └── lzma │ │ └── streams │ │ ├── DecodingTest.java │ │ └── RoundtripTest.java └── main │ └── java │ ├── org │ └── cservenak │ │ └── streams │ │ ├── Coder.java │ │ ├── CoderOutputStream.java │ │ ├── CoderInputStream.java │ │ └── CoderThread.java │ └── lzma │ ├── sdk │ ├── ICodeProgress.java │ ├── rangecoder │ │ ├── BitTreeDecoder.java │ │ ├── Decoder.java │ │ ├── BitTreeEncoder.java │ │ └── Encoder.java │ ├── CRC.java │ ├── lz │ │ ├── OutWindow.java │ │ ├── InWindow.java │ │ └── BinTree.java │ └── lzma │ │ ├── Base.java │ │ ├── Decoder.java │ │ └── Encoder.java │ └── streams │ ├── LzmaInputStream.java │ ├── LzmaDecoderWrapper.java │ ├── LzmaOutputStream.java │ └── LzmaEncoderWrapper.java ├── .gitignore ├── README.md ├── pom.xml └── LICENSE /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | -------------------------------------------------------------------------------- /src/test/resources/ajar.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jponge/lzma-java/HEAD/src/test/resources/ajar.jar -------------------------------------------------------------------------------- /src/test/resources/doc.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jponge/lzma-java/HEAD/src/test/resources/doc.pdf -------------------------------------------------------------------------------- /src/test/resources/hello.txt.lzma: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jponge/lzma-java/HEAD/src/test/resources/hello.txt.lzma -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignores for project 2 | # Language is Java 3 | # Build tool is Apache Maven3 4 | # IDE's used too 5 | # so, we have to ignore all the specifics of these above 6 | 7 | # Eclipse related 8 | .classpath 9 | .project 10 | .settings/ 11 | 12 | # Intellij 13 | .idea/ 14 | *.ipr 15 | *.iml 16 | *.iws 17 | 18 | # Maven related (and some plugins) 19 | target/ 20 | *.ser 21 | *.ec 22 | 23 | # Other 24 | .svn/ 25 | bin/ 26 | -------------------------------------------------------------------------------- /src/test/java/lzma/streams/DecodingTest.java: -------------------------------------------------------------------------------- 1 | package lzma.streams; 2 | 3 | 4 | import java.io.File; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.util.List; 8 | 9 | import org.apache.commons.io.FileUtils; 10 | import org.apache.commons.io.IOUtils; 11 | 12 | import junit.framework.TestCase; 13 | import lzma.sdk.lzma.Decoder; 14 | 15 | public class DecodingTest extends TestCase { 16 | 17 | public void testDecodeFileWithoutEndOfStreamMarker() throws IOException { 18 | final InputStream compressedFileStream = FileUtils 19 | .openInputStream(new File("target/test-classes/hello.txt.lzma")); 20 | 21 | @SuppressWarnings("unchecked") 22 | final List lines = IOUtils.readLines(new LzmaInputStream( 23 | compressedFileStream, new Decoder())); 24 | 25 | assertEquals(1, lines.size()); 26 | assertEquals("Hello World !", lines.get(0)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/org/cservenak/streams/Coder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Tamas Cservenak. All rights reserved. 3 | * 4 | * 5 | * http://www.cservenak.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | package org.cservenak.streams; 21 | 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | import java.io.OutputStream; 25 | 26 | public interface Coder 27 | { 28 | void code(InputStream in, OutputStream out) 29 | throws IOException; 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/lzma/sdk/ICodeProgress.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Julien Ponge. All rights reserved. 3 | * 4 | * 5 | * http://julien.ponge.info/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * This work is based on the LZMA SDK by Igor Pavlov. 20 | * The LZMA SDK is placed under the public domain, and can be obtained from 21 | * 22 | * http://www.7-zip.org/sdk.html 23 | * 24 | * The LzmaInputStream and LzmaOutputStream classes were inspired by the 25 | * work of Christopher League, although they are not derivative works. 26 | * 27 | * http://contrapunctus.net/league/haques/lzmajio/ 28 | */ 29 | 30 | package lzma.sdk; 31 | 32 | public interface ICodeProgress 33 | { 34 | public void setProgress(long inSize, long outSize); 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/lzma/streams/LzmaInputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011 Julien Ponge. All rights reserved. 3 | * 4 | * Portions Copyright (c) 2011 Tamas Cservenak. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package lzma.streams; 20 | 21 | import lzma.sdk.lzma.Decoder; 22 | import org.cservenak.streams.CoderInputStream; 23 | 24 | import java.io.IOException; 25 | import java.io.InputStream; 26 | 27 | /** 28 | * An input stream that uses LZMA compression. 29 | * 30 | * @author Julien Ponge 31 | * @author Tamas Cservenak 32 | */ 33 | public class LzmaInputStream 34 | extends CoderInputStream 35 | { 36 | public LzmaInputStream(final InputStream in, final Decoder lzmaDecoder) 37 | throws IOException 38 | { 39 | super(in, new LzmaDecoderWrapper(lzmaDecoder)); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/lzma/sdk/rangecoder/BitTreeDecoder.java: -------------------------------------------------------------------------------- 1 | package lzma.sdk.rangecoder; 2 | 3 | public class BitTreeDecoder 4 | { 5 | private final short[] Models; 6 | private final int NumBitLevels; 7 | 8 | public BitTreeDecoder(int numBitLevels) 9 | { 10 | NumBitLevels = numBitLevels; 11 | Models = new short[1 << numBitLevels]; 12 | } 13 | 14 | public void init() 15 | { 16 | Decoder.initBitModels(Models); 17 | } 18 | 19 | public int decode(Decoder rangeDecoder) throws java.io.IOException 20 | { 21 | int m = 1; 22 | for (int bitIndex = NumBitLevels; bitIndex != 0; bitIndex--) 23 | { 24 | m = (m << 1) + rangeDecoder.decodeBit(Models, m); 25 | } 26 | return m - (1 << NumBitLevels); 27 | } 28 | 29 | public int reverseDecode(Decoder rangeDecoder) throws java.io.IOException 30 | { 31 | int m = 1; 32 | int symbol = 0; 33 | for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++) 34 | { 35 | int bit = rangeDecoder.decodeBit(Models, m); 36 | m <<= 1; 37 | m += bit; 38 | symbol |= (bit << bitIndex); 39 | } 40 | return symbol; 41 | } 42 | 43 | public static int reverseDecode(short[] Models, int startIndex, 44 | Decoder rangeDecoder, int NumBitLevels) throws java.io.IOException 45 | { 46 | int m = 1; 47 | int symbol = 0; 48 | for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++) 49 | { 50 | int bit = rangeDecoder.decodeBit(Models, startIndex + m); 51 | m <<= 1; 52 | m += bit; 53 | symbol |= (bit << bitIndex); 54 | } 55 | return symbol; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/lzma/streams/LzmaDecoderWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Tamas Cservenak. All rights reserved. 3 | * 4 | * 5 | * http://www.cservenak.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | package lzma.streams; 21 | 22 | import lzma.sdk.lzma.Decoder; 23 | import org.cservenak.streams.Coder; 24 | 25 | import java.io.IOException; 26 | import java.io.InputStream; 27 | import java.io.OutputStream; 28 | 29 | public class LzmaDecoderWrapper 30 | implements Coder 31 | { 32 | private final Decoder decoder; 33 | 34 | public LzmaDecoderWrapper(final Decoder decoder) 35 | { 36 | this.decoder = decoder; 37 | } 38 | 39 | @Override 40 | public void code(final InputStream in, final OutputStream out) 41 | throws IOException 42 | { 43 | byte[] properties = new byte[5]; 44 | if (in.read(properties) != 5) 45 | { 46 | throw new IOException("LZMA file has no header!"); 47 | } 48 | 49 | if (!decoder.setDecoderProperties(properties)) 50 | { 51 | throw new IOException("Decoder properties cannot be set!"); 52 | } 53 | 54 | long outSize = 0; 55 | for (int i = 0; i < 8; i++) 56 | { 57 | int v = in.read(); 58 | if (v < 0) 59 | throw new IOException("Can't read stream size"); 60 | outSize |= ((long)v) << (8 * i); 61 | } 62 | 63 | if (!decoder.code(in, out, outSize)) 64 | { 65 | throw new IOException("Decoding unsuccessful!"); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/org/cservenak/streams/CoderOutputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Tamas Cservenak. All rights reserved. 3 | * 4 | * 5 | * http://www.cservenak.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | package org.cservenak.streams; 21 | 22 | import java.io.IOException; 23 | import java.io.OutputStream; 24 | 25 | public class CoderOutputStream 26 | extends OutputStream 27 | { 28 | private final CoderThread ct; 29 | 30 | private OutputStream out; 31 | 32 | protected CoderOutputStream(final OutputStream out, final Coder coder) 33 | throws IOException 34 | { 35 | this.ct = new CoderThread(coder, out); 36 | 37 | this.out = ct.getOutputStreamSink(); 38 | 39 | this.ct.start(); 40 | } 41 | 42 | public void write(int b) 43 | throws IOException 44 | { 45 | out.write(b); 46 | } 47 | 48 | public void write(byte b[]) 49 | throws IOException 50 | { 51 | write(b, 0, b.length); 52 | } 53 | 54 | public void write(byte b[], int off, int len) 55 | throws IOException 56 | { 57 | if ((off | len | (b.length - (len + off)) | (off + len)) < 0) 58 | { 59 | throw new IndexOutOfBoundsException(); 60 | } 61 | out.write(b, off, len); 62 | } 63 | 64 | public void flush() 65 | throws IOException 66 | { 67 | out.flush(); 68 | } 69 | 70 | public void close() 71 | throws IOException 72 | { 73 | try 74 | { 75 | flush(); 76 | } 77 | catch (IOException ignored) { 78 | // why do we swallow exception here?! 79 | } 80 | 81 | out.close(); 82 | 83 | try 84 | { 85 | ct.join(); 86 | } 87 | catch (InterruptedException e) 88 | { 89 | throw new IOException(e); 90 | } 91 | ct.checkForException(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/lzma/sdk/CRC.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Julien Ponge. All rights reserved. 3 | * 4 | * 5 | * http://julien.ponge.info/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * This work is based on the LZMA SDK by Igor Pavlov. 20 | * The LZMA SDK is placed under the public domain, and can be obtained from 21 | * 22 | * http://www.7-zip.org/sdk.html 23 | * 24 | * The LzmaInputStream and LzmaOutputStream classes were inspired by the 25 | * work of Christopher League, although they are not derivative works. 26 | * 27 | * http://contrapunctus.net/league/haques/lzmajio/ 28 | */ 29 | 30 | package lzma.sdk; 31 | 32 | public class CRC 33 | { 34 | static public int[] Table = new int[256]; 35 | 36 | static 37 | { 38 | for (int i = 0; i < 256; i++) 39 | { 40 | int r = i; 41 | for (int j = 0; j < 8; j++) 42 | { 43 | if ((r & 1) != 0) 44 | { 45 | r = (r >>> 1) ^ 0xEDB88320; 46 | } 47 | else 48 | { 49 | r >>>= 1; 50 | } 51 | } 52 | Table[i] = r; 53 | } 54 | } 55 | 56 | int _value = -1; 57 | 58 | public void init() 59 | { 60 | _value = -1; 61 | } 62 | 63 | public void update(byte[] data, int offset, int size) 64 | { 65 | for (int i = 0; i < size; i++) 66 | { 67 | _value = Table[(_value ^ data[offset + i]) & 0xFF] ^ (_value >>> 8); 68 | } 69 | } 70 | 71 | public void update(byte[] data) 72 | { 73 | int size = data.length; 74 | for (int i = 0; i < size; i++) 75 | { 76 | _value = Table[(_value ^ data[i]) & 0xFF] ^ (_value >>> 8); 77 | } 78 | } 79 | 80 | public void updateByte(int b) 81 | { 82 | _value = Table[(_value ^ b) & 0xFF] ^ (_value >>> 8); 83 | } 84 | 85 | public int getDigest() 86 | { 87 | return ~_value; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/lzma/sdk/rangecoder/Decoder.java: -------------------------------------------------------------------------------- 1 | package lzma.sdk.rangecoder; 2 | 3 | import java.io.IOException; 4 | 5 | public class Decoder 6 | { 7 | private static final int kTopMask = ~((1 << 24) - 1); 8 | 9 | private static final int kNumBitModelTotalBits = 11; 10 | private static final int kBitModelTotal = (1 << kNumBitModelTotalBits); 11 | private static final int kNumMoveBits = 5; 12 | 13 | private int Range; 14 | private int Code; 15 | 16 | private java.io.InputStream Stream; 17 | 18 | public final void setStream(java.io.InputStream stream) 19 | { 20 | Stream = stream; 21 | } 22 | 23 | public final void releaseStream() 24 | { 25 | Stream = null; 26 | } 27 | 28 | public final void init() throws IOException 29 | { 30 | Code = 0; 31 | Range = -1; 32 | for (int i = 0; i < 5; i++) 33 | { 34 | Code = (Code << 8) | Stream.read(); 35 | } 36 | } 37 | 38 | public final int decodeDirectBits(int numTotalBits) throws IOException 39 | { 40 | int result = 0; 41 | for (int i = numTotalBits; i != 0; i--) 42 | { 43 | Range >>>= 1; 44 | int t = ((Code - Range) >>> 31); 45 | Code -= Range & (t - 1); 46 | result = (result << 1) | (1 - t); 47 | 48 | if ((Range & kTopMask) == 0) 49 | { 50 | Code = (Code << 8) | Stream.read(); 51 | Range <<= 8; 52 | } 53 | } 54 | return result; 55 | } 56 | 57 | public int decodeBit(short[] probs, int index) throws IOException 58 | { 59 | int prob = probs[index]; 60 | int newBound = (Range >>> kNumBitModelTotalBits) * prob; 61 | if ((Code ^ 0x80000000) < (newBound ^ 0x80000000)) 62 | { 63 | Range = newBound; 64 | probs[index] = (short) (prob + ((kBitModelTotal - prob) >>> kNumMoveBits)); 65 | if ((Range & kTopMask) == 0) 66 | { 67 | Code = (Code << 8) | Stream.read(); 68 | Range <<= 8; 69 | } 70 | return 0; 71 | } 72 | else 73 | { 74 | Range -= newBound; 75 | Code -= newBound; 76 | probs[index] = (short) (prob - ((prob) >>> kNumMoveBits)); 77 | if ((Range & kTopMask) == 0) 78 | { 79 | Code = (Code << 8) | Stream.read(); 80 | Range <<= 8; 81 | } 82 | return 1; 83 | } 84 | } 85 | 86 | public static void initBitModels(short[] probs) 87 | { 88 | for (int i = 0; i < probs.length; i++) 89 | { 90 | probs[i] = (kBitModelTotal >>> 1); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/org/cservenak/streams/CoderInputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Tamas Cservenak. All rights reserved. 3 | * 4 | * 5 | * http://www.cservenak.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | package org.cservenak.streams; 21 | 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | 25 | public class CoderInputStream 26 | extends InputStream 27 | { 28 | private final CoderThread ct; 29 | 30 | private volatile InputStream in; 31 | 32 | protected CoderInputStream(final InputStream in, final Coder coder) 33 | throws IOException 34 | { 35 | this.ct = new CoderThread(coder, in); 36 | 37 | this.in = ct.getInputStreamSink(); 38 | 39 | this.ct.start(); 40 | } 41 | 42 | @Override 43 | public int read() 44 | throws IOException 45 | { 46 | return in.read(); 47 | } 48 | 49 | @Override 50 | public int read(byte b[]) 51 | throws IOException 52 | { 53 | return read(b, 0, b.length); 54 | } 55 | 56 | @Override 57 | public int read(byte b[], int off, int len) 58 | throws IOException 59 | { 60 | return in.read(b, off, len); 61 | } 62 | 63 | @Override 64 | public long skip(long n) 65 | throws IOException 66 | { 67 | return in.skip(n); 68 | } 69 | 70 | @Override 71 | public int available() 72 | throws IOException 73 | { 74 | return in.available(); 75 | } 76 | 77 | @Override 78 | public void close() 79 | throws IOException 80 | { 81 | in.close(); 82 | 83 | try 84 | { 85 | ct.join(); 86 | } 87 | catch (InterruptedException e) 88 | { 89 | throw new IOException(e); 90 | } 91 | 92 | ct.checkForException(); 93 | } 94 | 95 | @Override 96 | public synchronized void mark(int readlimit) 97 | { 98 | in.mark(readlimit); 99 | } 100 | 101 | @Override 102 | public synchronized void reset() 103 | throws IOException 104 | { 105 | in.reset(); 106 | } 107 | 108 | @Override 109 | public boolean markSupported() 110 | { 111 | return in.markSupported(); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/lzma/sdk/rangecoder/BitTreeEncoder.java: -------------------------------------------------------------------------------- 1 | package lzma.sdk.rangecoder; 2 | 3 | import java.io.IOException; 4 | 5 | public class BitTreeEncoder 6 | { 7 | private final short[] Models; 8 | private final int NumBitLevels; 9 | 10 | public BitTreeEncoder(int numBitLevels) 11 | { 12 | NumBitLevels = numBitLevels; 13 | Models = new short[1 << numBitLevels]; 14 | } 15 | 16 | public void init() 17 | { 18 | Decoder.initBitModels(Models); 19 | } 20 | 21 | public void encode(Encoder rangeEncoder, int symbol) throws IOException 22 | { 23 | int m = 1; 24 | for (int bitIndex = NumBitLevels; bitIndex != 0;) 25 | { 26 | bitIndex--; 27 | int bit = (symbol >>> bitIndex) & 1; 28 | rangeEncoder.encode(Models, m, bit); 29 | m = (m << 1) | bit; 30 | } 31 | } 32 | 33 | public void reverseEncode(Encoder rangeEncoder, int symbol) throws IOException 34 | { 35 | int m = 1; 36 | for (int i = 0; i < NumBitLevels; i++) 37 | { 38 | int bit = symbol & 1; 39 | rangeEncoder.encode(Models, m, bit); 40 | m = (m << 1) | bit; 41 | symbol >>= 1; 42 | } 43 | } 44 | 45 | public int getPrice(int symbol) 46 | { 47 | int price = 0; 48 | int m = 1; 49 | for (int bitIndex = NumBitLevels; bitIndex != 0;) 50 | { 51 | bitIndex--; 52 | int bit = (symbol >>> bitIndex) & 1; 53 | price += Encoder.getPrice(Models[m], bit); 54 | m = (m << 1) + bit; 55 | } 56 | return price; 57 | } 58 | 59 | public int reverseGetPrice(int symbol) 60 | { 61 | int price = 0; 62 | int m = 1; 63 | for (int i = NumBitLevels; i != 0; i--) 64 | { 65 | int bit = symbol & 1; 66 | symbol >>>= 1; 67 | price += Encoder.getPrice(Models[m], bit); 68 | m = (m << 1) | bit; 69 | } 70 | return price; 71 | } 72 | 73 | public static int reverseGetPrice(short[] Models, int startIndex, 74 | int NumBitLevels, int symbol) 75 | { 76 | int price = 0; 77 | int m = 1; 78 | for (int i = NumBitLevels; i != 0; i--) 79 | { 80 | int bit = symbol & 1; 81 | symbol >>>= 1; 82 | price += Encoder.getPrice(Models[startIndex + m], bit); 83 | m = (m << 1) | bit; 84 | } 85 | return price; 86 | } 87 | 88 | public static void reverseEncode(short[] Models, int startIndex, 89 | Encoder rangeEncoder, int NumBitLevels, int symbol) throws IOException 90 | { 91 | int m = 1; 92 | for (int i = 0; i < NumBitLevels; i++) 93 | { 94 | int bit = symbol & 1; 95 | rangeEncoder.encode(Models, startIndex + m, bit); 96 | m = (m << 1) | bit; 97 | symbol >>= 1; 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/lzma/sdk/lz/OutWindow.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Julien Ponge. All rights reserved. 3 | * 4 | * 5 | * http://julien.ponge.info/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * This work is based on the LZMA SDK by Igor Pavlov. 20 | * The LZMA SDK is placed under the public domain, and can be obtained from 21 | * 22 | * http://www.7-zip.org/sdk.html 23 | * 24 | * The LzmaInputStream and LzmaOutputStream classes were inspired by the 25 | * work of Christopher League, although they are not derivative works. 26 | * 27 | * http://contrapunctus.net/league/haques/lzmajio/ 28 | */ 29 | 30 | package lzma.sdk.lz; 31 | 32 | import java.io.IOException; 33 | 34 | public class OutWindow 35 | { 36 | private byte[] _buffer; 37 | private int _pos; 38 | private int _windowSize = 0; 39 | private int _streamPos; 40 | private java.io.OutputStream _stream; 41 | 42 | public void create(int windowSize) 43 | { 44 | if (_buffer == null || _windowSize != windowSize) 45 | { 46 | _buffer = new byte[windowSize]; 47 | } 48 | _windowSize = windowSize; 49 | _pos = 0; 50 | _streamPos = 0; 51 | } 52 | 53 | public void setStream(java.io.OutputStream stream) throws IOException 54 | { 55 | releaseStream(); 56 | _stream = stream; 57 | } 58 | 59 | public void releaseStream() throws IOException 60 | { 61 | flush(); 62 | _stream = null; 63 | } 64 | 65 | public void init(boolean solid) 66 | { 67 | if (!solid) 68 | { 69 | _streamPos = 0; 70 | _pos = 0; 71 | } 72 | } 73 | 74 | public void flush() throws IOException 75 | { 76 | int size = _pos - _streamPos; 77 | if (size == 0) 78 | { 79 | return; 80 | } 81 | _stream.write(_buffer, _streamPos, size); 82 | if (_pos >= _windowSize) 83 | { 84 | _pos = 0; 85 | } 86 | _streamPos = _pos; 87 | } 88 | 89 | public void copyBlock(int distance, int len) throws IOException 90 | { 91 | int pos = _pos - distance - 1; 92 | if (pos < 0) 93 | { 94 | pos += _windowSize; 95 | } 96 | for (; len != 0; len--) 97 | { 98 | if (pos >= _windowSize) 99 | { 100 | pos = 0; 101 | } 102 | _buffer[_pos++] = _buffer[pos++]; 103 | if (_pos >= _windowSize) 104 | { 105 | flush(); 106 | } 107 | } 108 | } 109 | 110 | public void putByte(byte b) throws IOException 111 | { 112 | _buffer[_pos++] = b; 113 | if (_pos >= _windowSize) 114 | { 115 | flush(); 116 | } 117 | } 118 | 119 | public byte getByte(int distance) 120 | { 121 | int pos = _pos - distance - 1; 122 | if (pos < 0) 123 | { 124 | pos += _windowSize; 125 | } 126 | return _buffer[pos]; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/main/java/lzma/sdk/lzma/Base.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Julien Ponge. All rights reserved. 3 | * 4 | * 5 | * http://julien.ponge.info/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * This work is based on the LZMA SDK by Igor Pavlov. 20 | * The LZMA SDK is placed under the public domain, and can be obtained from 21 | * 22 | * http://www.7-zip.org/sdk.html 23 | * 24 | * The LzmaInputStream and LzmaOutputStream classes were inspired by the 25 | * work of Christopher League, although they are not derivative works. 26 | * 27 | * http://contrapunctus.net/league/haques/lzmajio/ 28 | */ 29 | 30 | package lzma.sdk.lzma; 31 | 32 | public class Base 33 | { 34 | public static final int kNumRepDistances = 4; 35 | public static final int kNumStates = 12; 36 | 37 | public static int stateInit() 38 | { 39 | return 0; 40 | } 41 | 42 | public static int stateUpdateChar(int index) 43 | { 44 | if (index < 4) 45 | { 46 | return 0; 47 | } 48 | if (index < 10) 49 | { 50 | return index - 3; 51 | } 52 | return index - 6; 53 | } 54 | 55 | public static int stateUpdateMatch(int index) 56 | { 57 | return (index < 7 ? 7 : 10); 58 | } 59 | 60 | public static int stateUpdateRep(int index) 61 | { 62 | return (index < 7 ? 8 : 11); 63 | } 64 | 65 | public static int stateUpdateShortRep(int index) 66 | { 67 | return (index < 7 ? 9 : 11); 68 | } 69 | 70 | public static boolean stateIsCharState(int index) 71 | { 72 | return index < 7; 73 | } 74 | 75 | public static final int kNumPosSlotBits = 6; 76 | // public static final int kDicLogSizeMax = 28; 77 | // public static final int kDistTableSizeMax = kDicLogSizeMax * 2; 78 | 79 | public static final int kNumLenToPosStatesBits = 2; // it's for speed optimization 80 | public static final int kNumLenToPosStates = 1 << kNumLenToPosStatesBits; 81 | 82 | public static final int kMatchMinLen = 2; 83 | 84 | public static int getLenToPosState(int len) 85 | { 86 | len -= kMatchMinLen; 87 | if (len < kNumLenToPosStates) 88 | { 89 | return len; 90 | } 91 | return kNumLenToPosStates - 1; 92 | } 93 | 94 | public static final int kNumAlignBits = 4; 95 | public static final int kAlignTableSize = 1 << kNumAlignBits; 96 | public static final int kAlignMask = (kAlignTableSize - 1); 97 | 98 | public static final int kStartPosModelIndex = 4; 99 | public static final int kEndPosModelIndex = 14; 100 | 101 | public static final int kNumFullDistances = 1 << (kEndPosModelIndex / 2); 102 | 103 | public static final int kNumLitPosStatesBitsEncodingMax = 4; 104 | public static final int kNumLitContextBitsMax = 8; 105 | 106 | public static final int kNumPosStatesBitsMax = 4; 107 | public static final int kNumPosStatesMax = (1 << kNumPosStatesBitsMax); 108 | public static final int kNumPosStatesBitsEncodingMax = 4; 109 | public static final int kNumPosStatesEncodingMax = (1 << kNumPosStatesBitsEncodingMax); 110 | 111 | public static final int kNumLowLenBits = 3; 112 | public static final int kNumMidLenBits = 3; 113 | public static final int kNumHighLenBits = 8; 114 | public static final int kNumLowLenSymbols = 1 << kNumLowLenBits; 115 | public static final int kNumMidLenSymbols = 1 << kNumMidLenBits; 116 | public static final int kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols + 117 | (1 << kNumHighLenBits); 118 | public static final int kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1; 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/lzma/streams/LzmaOutputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011 Julien Ponge. All rights reserved. 3 | * 4 | * Portions Copyright (c) 2011 Tamas Cservenak. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package lzma.streams; 20 | 21 | import lzma.sdk.lzma.Encoder; 22 | import org.cservenak.streams.CoderOutputStream; 23 | 24 | import java.io.IOException; 25 | import java.io.OutputStream; 26 | 27 | import static lzma.sdk.lzma.Encoder.EMatchFinderTypeBT2; 28 | import static lzma.sdk.lzma.Encoder.EMatchFinderTypeBT4; 29 | 30 | /** 31 | * An output stream that uses LZMA compression. 32 | * 33 | * @author Julien Ponge 34 | * @author Tamas Cservenak 35 | */ 36 | public class LzmaOutputStream 37 | extends CoderOutputStream 38 | { 39 | public LzmaOutputStream(final OutputStream out, final LzmaEncoderWrapper wrapper) 40 | throws IOException 41 | { 42 | super(out, wrapper); 43 | } 44 | 45 | public LzmaOutputStream(final OutputStream out, final Encoder lzmaEncoder) 46 | throws IOException 47 | { 48 | this(out, new LzmaEncoderWrapper(lzmaEncoder)); 49 | } 50 | 51 | /** 52 | * A convenient builder that makes it easier to configure the LZMA encoder. 53 | * Default values: 54 | *
    55 | *
  • dictionnary size: max
  • 56 | *
  • end marker mode: true
  • 57 | *
  • match finder: BT4
  • 58 | *
  • number of fast bytes: 0x20
  • 59 | *
60 | */ 61 | public static class Builder 62 | { 63 | private final OutputStream out; 64 | 65 | private int dictionnarySize = 1 << 23; 66 | 67 | private boolean endMarkerMode = true; 68 | 69 | private int matchFinder = EMatchFinderTypeBT4; 70 | 71 | private int numFastBytes = 0x20; 72 | 73 | public Builder(OutputStream out) 74 | { 75 | this.out = out; 76 | } 77 | 78 | public Builder useMaximalDictionarySize() 79 | { 80 | dictionnarySize = 1 << 28; 81 | return this; 82 | } 83 | 84 | public Builder useMediumDictionarySize() 85 | { 86 | dictionnarySize = 1 << 15; 87 | return this; 88 | } 89 | 90 | public Builder useMinimalDictionarySize() 91 | { 92 | dictionnarySize = 1; 93 | return this; 94 | } 95 | 96 | public Builder useEndMarkerMode(boolean endMarkerMode) 97 | { 98 | this.endMarkerMode = endMarkerMode; 99 | return this; 100 | } 101 | 102 | public Builder useBT4MatchFinder() 103 | { 104 | matchFinder = EMatchFinderTypeBT4; 105 | return this; 106 | } 107 | 108 | public Builder useBT2MatchFinder() 109 | { 110 | matchFinder = EMatchFinderTypeBT2; 111 | return this; 112 | } 113 | 114 | public Builder useMinimalFastBytes() 115 | { 116 | numFastBytes = 5; 117 | return this; 118 | } 119 | 120 | public Builder useMediumFastBytes() 121 | { 122 | numFastBytes = 0x20; 123 | return this; 124 | } 125 | 126 | public Builder useMaximalFastBytes() 127 | { 128 | numFastBytes = 273; 129 | return this; 130 | } 131 | 132 | public LzmaOutputStream build() throws IOException 133 | { 134 | Encoder encoder = new Encoder(); 135 | 136 | encoder.setDictionarySize(dictionnarySize); 137 | encoder.setEndMarkerMode(endMarkerMode); 138 | encoder.setMatchFinder(matchFinder); 139 | encoder.setNumFastBytes(numFastBytes); 140 | 141 | return new LzmaOutputStream(out, encoder); 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/main/java/org/cservenak/streams/CoderThread.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Tamas Cservenak. All rights reserved. 3 | * 4 | * 5 | * http://www.cservenak.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | package org.cservenak.streams; 21 | 22 | import java.io.*; 23 | 24 | public class CoderThread 25 | extends Thread 26 | { 27 | private final PipedInputStream inSink; 28 | 29 | private final PipedOutputStream outSink; 30 | 31 | private final Runnable workhorse; 32 | 33 | private Throwable throwable; 34 | 35 | public CoderThread(final Coder coder, final InputStream in) 36 | throws IOException 37 | { 38 | this.inSink = new PipedInputStream(); 39 | this.outSink = new PipedOutputStream(inSink); 40 | this.workhorse = new Runnable() 41 | { 42 | public void run() 43 | { 44 | try 45 | { 46 | coder.code(in, outSink); 47 | 48 | flush(outSink); 49 | } 50 | catch (Throwable e) 51 | { 52 | throwable = e; 53 | } 54 | finally 55 | { 56 | close(outSink); 57 | } 58 | } 59 | }; 60 | } 61 | 62 | public CoderThread(final Coder coder, final OutputStream out) 63 | throws IOException 64 | { 65 | this.outSink = new PipedOutputStream(); 66 | this.inSink = new PipedInputStream(outSink); 67 | this.workhorse = new Runnable() 68 | { 69 | public void run() 70 | { 71 | try 72 | { 73 | coder.code(inSink, out); 74 | 75 | flush(out); 76 | } 77 | catch (Throwable e) 78 | { 79 | throwable = e; 80 | } 81 | finally 82 | { 83 | close(inSink); 84 | } 85 | } 86 | }; 87 | } 88 | 89 | public void run() 90 | { 91 | workhorse.run(); 92 | } 93 | 94 | // == 95 | 96 | public Throwable getThrowable() 97 | { 98 | return throwable; 99 | } 100 | 101 | public void checkForException() 102 | throws IOException 103 | { 104 | if (null != throwable) 105 | { 106 | if (throwable instanceof IOException) 107 | { 108 | throw (IOException) throwable; 109 | } 110 | else 111 | { 112 | throw new IOException(throwable); 113 | } 114 | } 115 | } 116 | 117 | public PipedInputStream getInputStreamSink() 118 | { 119 | return inSink; 120 | } 121 | 122 | public PipedOutputStream getOutputStreamSink() 123 | { 124 | return outSink; 125 | } 126 | 127 | // == 128 | 129 | protected boolean flush(Flushable flushable) 130 | { 131 | if (flushable != null) 132 | { 133 | try 134 | { 135 | flushable.flush(); 136 | 137 | return true; 138 | } 139 | catch (IOException e) 140 | { 141 | // mute 142 | } 143 | } 144 | 145 | return false; 146 | } 147 | 148 | protected boolean close(Closeable closeable) 149 | { 150 | if (closeable != null) 151 | { 152 | try 153 | { 154 | closeable.close(); 155 | 156 | return true; 157 | } 158 | catch (IOException e) 159 | { 160 | // mute 161 | } 162 | } 163 | 164 | return false; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/main/java/lzma/streams/LzmaEncoderWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011 Tamas Cservenak. All rights reserved. 3 | * 4 | * 5 | * http://www.cservenak.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | package lzma.streams; 21 | 22 | import lzma.sdk.lzma.Encoder; 23 | import org.cservenak.streams.Coder; 24 | 25 | import java.io.IOException; 26 | import java.io.InputStream; 27 | import java.io.OutputStream; 28 | 29 | import static lzma.sdk.lzma.Encoder.EMatchFinderTypeBT2; 30 | import static lzma.sdk.lzma.Encoder.EMatchFinderTypeBT4; 31 | 32 | public class LzmaEncoderWrapper 33 | implements Coder 34 | { 35 | private final static byte[] MINUS_ONE = new byte[8]; 36 | static { 37 | for (int i = 0; i < MINUS_ONE.length; ++i) { 38 | MINUS_ONE[i] = (byte) -1; 39 | } 40 | } 41 | 42 | private final Encoder encoder; 43 | 44 | public LzmaEncoderWrapper(final Encoder encoder) 45 | { 46 | this.encoder = encoder; 47 | } 48 | 49 | @Override 50 | public void code(final InputStream in, final OutputStream out) 51 | throws IOException 52 | { 53 | encoder.writeCoderProperties(out); 54 | // write -1 as "unknown" for file size 55 | out.write(MINUS_ONE); 56 | encoder.code(in, out, -1, -1, null); 57 | } 58 | 59 | /** 60 | * A convenient builder that makes it easier to configure the LZMA encoder. Default values: 61 | *
    62 | *
  • dictionary size: 23 (almost max, so is memory hungry)
  • 63 | *
  • end marker mode: true
  • 64 | *
  • match finder: BT4
  • 65 | *
  • number of fast bytes: 0x20
  • 66 | *
67 | */ 68 | public static class Builder 69 | { 70 | private int dictionnarySize = 1 << 23; 71 | 72 | private boolean endMarkerMode = true; 73 | 74 | private int matchFinder = EMatchFinderTypeBT4; 75 | 76 | private int numFastBytes = 0x20; 77 | 78 | public Builder useMaximalDictionarySize() 79 | { 80 | dictionnarySize = 1 << 28; 81 | return this; 82 | } 83 | 84 | public Builder useMediumDictionarySize() 85 | { 86 | dictionnarySize = 1 << 15; 87 | return this; 88 | } 89 | 90 | public Builder useMinimalDictionarySize() 91 | { 92 | dictionnarySize = 1; 93 | return this; 94 | } 95 | 96 | public Builder useEndMarkerMode(boolean endMarkerMode) 97 | { 98 | this.endMarkerMode = endMarkerMode; 99 | return this; 100 | } 101 | 102 | public Builder useBT4MatchFinder() 103 | { 104 | matchFinder = EMatchFinderTypeBT4; 105 | return this; 106 | } 107 | 108 | public Builder useBT2MatchFinder() 109 | { 110 | matchFinder = EMatchFinderTypeBT2; 111 | return this; 112 | } 113 | 114 | public Builder useMinimalFastBytes() 115 | { 116 | numFastBytes = 5; 117 | return this; 118 | } 119 | 120 | public Builder useMediumFastBytes() 121 | { 122 | numFastBytes = 0x20; 123 | return this; 124 | } 125 | 126 | public Builder useMaximalFastBytes() 127 | { 128 | numFastBytes = 273; 129 | return this; 130 | } 131 | 132 | public LzmaEncoderWrapper build() 133 | { 134 | Encoder encoder = new Encoder(); 135 | 136 | encoder.setDictionarySize(dictionnarySize); 137 | encoder.setEndMarkerMode(endMarkerMode); 138 | encoder.setMatchFinder(matchFinder); 139 | encoder.setNumFastBytes(numFastBytes); 140 | 141 | return new LzmaEncoderWrapper(encoder); 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/main/java/lzma/sdk/rangecoder/Encoder.java: -------------------------------------------------------------------------------- 1 | package lzma.sdk.rangecoder; 2 | 3 | import java.io.IOException; 4 | 5 | public class Encoder 6 | { 7 | private static final int kTopMask = ~((1 << 24) - 1); 8 | 9 | private static final int kNumBitModelTotalBits = 11; 10 | private static final int kBitModelTotal = (1 << kNumBitModelTotalBits); 11 | private static final int kNumMoveBits = 5; 12 | 13 | private java.io.OutputStream Stream; 14 | 15 | private long Low; 16 | private int Range; 17 | private int _cacheSize; 18 | private int _cache; 19 | 20 | private long _position; 21 | 22 | public void setStream(java.io.OutputStream stream) 23 | { 24 | Stream = stream; 25 | } 26 | 27 | public void releaseStream() 28 | { 29 | Stream = null; 30 | } 31 | 32 | public void init() 33 | { 34 | _position = 0; 35 | Low = 0; 36 | Range = -1; 37 | _cacheSize = 1; 38 | _cache = 0; 39 | } 40 | 41 | public void flushData() throws IOException 42 | { 43 | for (int i = 0; i < 5; i++) 44 | { 45 | shiftLow(); 46 | } 47 | } 48 | 49 | public void flushStream() throws IOException 50 | { 51 | Stream.flush(); 52 | } 53 | 54 | void shiftLow() throws IOException 55 | { 56 | int LowHi = (int) (Low >>> 32); 57 | if (LowHi != 0 || Low < 0xFF000000L) 58 | { 59 | _position += _cacheSize; 60 | int temp = _cache; 61 | do 62 | { 63 | Stream.write(temp + LowHi); 64 | temp = 0xFF; 65 | } 66 | while (--_cacheSize != 0); 67 | _cache = (((int) Low) >>> 24); 68 | } 69 | _cacheSize++; 70 | Low = (Low & 0xFFFFFF) << 8; 71 | } 72 | 73 | public void encodeDirectBits(int v, int numTotalBits) throws IOException 74 | { 75 | for (int i = numTotalBits - 1; i >= 0; i--) 76 | { 77 | Range >>>= 1; 78 | if (((v >>> i) & 1) == 1) 79 | { 80 | Low += Range; 81 | } 82 | if ((Range & Encoder.kTopMask) == 0) 83 | { 84 | Range <<= 8; 85 | shiftLow(); 86 | } 87 | } 88 | } 89 | 90 | 91 | public long getProcessedSizeAdd() 92 | { 93 | return _cacheSize + _position + 4; 94 | } 95 | 96 | 97 | private static final int kNumMoveReducingBits = 2; 98 | public static final int kNumBitPriceShiftBits = 6; 99 | 100 | public static void initBitModels(short[] probs) 101 | { 102 | for (int i = 0; i < probs.length; i++) 103 | { 104 | probs[i] = (kBitModelTotal >>> 1); 105 | } 106 | } 107 | 108 | public void encode(short[] probs, int index, int symbol) throws IOException 109 | { 110 | int prob = probs[index]; 111 | int newBound = (Range >>> kNumBitModelTotalBits) * prob; 112 | if (symbol == 0) 113 | { 114 | Range = newBound; 115 | probs[index] = (short) (prob + ((kBitModelTotal - prob) >>> kNumMoveBits)); 116 | } 117 | else 118 | { 119 | Low += (newBound & 0xFFFFFFFFL); 120 | Range -= newBound; 121 | probs[index] = (short) (prob - ((prob) >>> kNumMoveBits)); 122 | } 123 | if ((Range & kTopMask) == 0) 124 | { 125 | Range <<= 8; 126 | shiftLow(); 127 | } 128 | } 129 | 130 | private static final int[] ProbPrices = new int[kBitModelTotal >>> kNumMoveReducingBits]; 131 | 132 | static 133 | { 134 | int kNumBits = (kNumBitModelTotalBits - kNumMoveReducingBits); 135 | for (int i = kNumBits - 1; i >= 0; i--) 136 | { 137 | int start = 1 << (kNumBits - i - 1); 138 | int end = 1 << (kNumBits - i); 139 | for (int j = start; j < end; j++) 140 | { 141 | ProbPrices[j] = (i << kNumBitPriceShiftBits) + 142 | (((end - j) << kNumBitPriceShiftBits) >>> (kNumBits - i - 1)); 143 | } 144 | } 145 | } 146 | 147 | static public int getPrice(int Prob, int symbol) 148 | { 149 | return ProbPrices[(((Prob - symbol) ^ ((-symbol))) & (kBitModelTotal - 1)) >>> kNumMoveReducingBits]; 150 | } 151 | 152 | static public int getPrice0(int Prob) 153 | { 154 | return ProbPrices[Prob >>> kNumMoveReducingBits]; 155 | } 156 | 157 | static public int getPrice1(int Prob) 158 | { 159 | return ProbPrices[(kBitModelTotal - Prob) >>> kNumMoveReducingBits]; 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Important: this project is not maintained anymore.** 2 | 3 | You should look at the [Apache Commons Compress project](https://commons.apache.org/proper/commons-compress/) 4 | for a rich set of supported compression formats, including LZMA. 5 | 6 | 7 | # LZMA library for Java # 8 | 9 | [![Build Status](https://secure.travis-ci.org/jponge/lzma-java.png)](http://travis-ci.org/jponge/lzma-java) 10 | 11 | [http://jponge.github.com/lzma-java](http://jponge.github.com/lzma-java) 12 | 13 | This library provides LZMA compression for applications that run on the Java platform. 14 | 15 | ## Background ## 16 | 17 | This library is based on the [Java LZMA SDK](http://www.7-zip.org/sdk.html) by Igor Pavlov. 18 | It provides some deserved enhancements. 19 | 20 | While the original code works just fine, it has some serious issues for Java developers: 21 | 22 | * this is a straight port of non-object, procedural code written in C to Java, and 23 | * the code does not follow Java conventions (e.g., methods names start by 24 | capital letters) 25 | * configuration of the LZMA encoder and decoders require passing around 26 | arrays and numbers for which no proper documentation or constants exists 27 | other than source code, and 28 | * ...there is no stream api to plug into `java.io` streams. 29 | 30 | There is unfortunately no public description of the LZMA algorithms other than source code, 31 | so a rewrite was clearly a hard task. I decided to create this library using the following 32 | methodology. 33 | 34 | 1. Import the Java LZMA SDK code. 35 | 2. Convert methods and package names to Java conventions. 36 | 3. Reformat the code and organize imports. 37 | 4. Remove the useless (at least in a library) command-line interface classes. 38 | 5. Run static code analysis to clean the code (unused variables, unusued parameters, 39 | unused methods, expressions simplifications and more). 40 | 6. Do some profiling. 41 | 7. Build a streaming api that would fit into `java.io` streams. 42 | 8. Provide some higher-level abstractions to the LZMA encoder / decoders configuration. 43 | 44 | Although not a derivate work, the streaming api classes were inspired from 45 | [the work of Christopher League](http://contrapunctus.net/league/haques/lzmajio/). I reused 46 | his technique of fake streams and working threads to pass the data around between 47 | encoders/decoders and "normal" Java streams. 48 | 49 | ## Using from Maven ## 50 | 51 | The releases are pushed to Maven Central. Add the dependency as follows: 52 | 53 | 54 | com.github.jponge 55 | lzma-java 56 | 1.2 57 | 58 | 59 | ## Usage ## 60 | 61 | There are two main Java package hierarchies: 62 | 63 | * `lzma.sdk` is the (reworked) Java LZMA SDK code, and 64 | * `lzma.streams` contains the `LzmaInputStream` and `LzmaInputStream` classes. 65 | 66 | You will probably only be interested in using the `lzma.streams` package. The two 67 | stream classes use the good practices of constructor dependency injection, and you will 68 | need to pass them the decorated streams and LZMA encoder / decoders from the SDK. 69 | 70 | You can simply instanciate a `Decoder` and pass it to the constructor of `LzmaInputStream` 71 | without specifying further configuration: it will read it from the input stream. 72 | 73 | The `Encoder` class that `LzmaOutputStream` depends on needs some configuration. You can 74 | either do it manually (checkout the `Encoder` class to guess what those integer values mean!), 75 | or you can use the `LzmaOutputStream.Builder` class which makes it much easier to configure. 76 | 77 | The following code is from a unit test. It should make the basic usage of the library relatively 78 | obvious: 79 | 80 | public void test_round_trip() throws IOException 81 | { 82 | final File sourceFile = new File("LICENSE"); 83 | final File compressed = File.createTempFile("lzma-java", "compressed"); 84 | final File unCompressed = File.createTempFile("lzma-java", "uncompressed"); 85 | 86 | final LzmaOutputStream compressedOut = new LzmaOutputStream.Builder( 87 | new BufferedOutputStream(new FileOutputStream(compressed))) 88 | .useMaximalDictionarySize() 89 | .useEndMarkerMode(true) 90 | .useBT4MatchFinder() 91 | .build(); 92 | 93 | final InputStream sourceIn = new BufferedInputStream(new FileInputStream(sourceFile)); 94 | 95 | copy(sourceIn, compressedOut); 96 | sourceIn.close(); 97 | compressedOut.close(); 98 | 99 | final LzmaInputStream compressedIn = new LzmaInputStream( 100 | new BufferedInputStream(new FileInputStream(compressed)), 101 | new Decoder()); 102 | 103 | final OutputStream uncompressedOut = new BufferedOutputStream( 104 | new FileOutputStream(unCompressed)); 105 | 106 | copy(compressedIn, uncompressedOut); 107 | compressedIn.close(); 108 | uncompressedOut.close(); 109 | 110 | assertTrue(contentEquals(sourceFile, unCompressed)); 111 | assertFalse(contentEquals(sourceFile, compressed)); 112 | } 113 | 114 | ## License ## 115 | 116 | The LZMA SDK is in the public domain. I relicensed the whole under the liberal 117 | [Apache License Version 2.0](http://www.apache.org/licenses/LICENSE-2.0). 118 | 119 | ## Contact ## 120 | 121 | * julien.ponge@gmail.com 122 | * [http://julien.ponge.info/](http://julien.ponge.info/) 123 | 124 | The code, downloads and issue trackers are made available from GitHub at 125 | [http://github.com/jponge/lzma-java](http://github.com/jponge/lzma-java). 126 | Do not hesitate to contribute by forking and asking for pulls! 127 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.0.0 5 | 6 | 7 | org.sonatype.oss 8 | oss-parent 9 | 7 10 | 11 | 12 | com.github.jponge 13 | lzma-java 14 | 15 | jar 16 | 1.4-SNAPSHOT 17 | 18 | LZMA Java 19 | LZMA library for Java 20 | http://jponge.github.com/lzma-java 21 | 22 | 23 | 24 | Apache License Version 2.0 25 | http://www.apache.org/licenses/LICENSE-2.0.txt 26 | repo 27 | 28 | 29 | 30 | 31 | 32 | jponge 33 | Julien Ponge 34 | julien.ponge@gmail.com 35 | http://julien.ponge.info/ 36 | 37 | developer 38 | 39 | 40 | 41 | cstamas 42 | Tamas Cservenak 43 | tamas@cservenak.com 44 | http://www.cservenak.com/ 45 | 46 | contributor 47 | 48 | 49 | 50 | lauri.hahne 51 | Lauri Hahne 52 | lauri.hahne@tut.fi 53 | 54 | contributor 55 | 56 | 57 | 58 | 59 | 60 | 61 | junit 62 | junit 63 | 4.7 64 | test 65 | 66 | 67 | commons-io 68 | commons-io 69 | 1.4 70 | test 71 | 72 | 73 | 74 | 75 | UTF-8 76 | 77 | 78 | 79 | scm:git:git://github.com/jponge/lzma-java.git 80 | scm:git:git://github.com/jponge/lzma-java.git 81 | http://github.com/jponge/lzma-java/tree/master 82 | 83 | 84 | 85 | GitHub 86 | http://github.com/jponge/lzma-java/issues 87 | 88 | 89 | 90 | 91 | 92 | org.apache.maven.plugins 93 | maven-surefire-plugin 94 | 2.7.1 95 | 96 | -Xms256m -Xmx256m 97 | 98 | 99 | 100 | org.apache.maven.plugins 101 | maven-compiler-plugin 102 | 2.3.2 103 | 104 | 1.6 105 | 1.6 106 | 107 | 108 | 109 | org.apache.maven.plugins 110 | maven-assembly-plugin 111 | 2.1 112 | 113 | 114 | bin 115 | src 116 | 117 | 118 | 119 | 120 | org.apache.maven.plugins 121 | maven-release-plugin 122 | 2.1 123 | 124 | true 125 | false 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | release-sign-artifacts 134 | 135 | 136 | performRelease 137 | true 138 | 139 | 140 | 141 | 142 | 143 | org.apache.maven.plugins 144 | maven-gpg-plugin 145 | 1.1 146 | 147 | 148 | install 149 | 150 | sign 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /src/main/java/lzma/sdk/lz/InWindow.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Julien Ponge. All rights reserved. 3 | * 4 | * 5 | * http://julien.ponge.info/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * This work is based on the LZMA SDK by Igor Pavlov. 20 | * The LZMA SDK is placed under the public domain, and can be obtained from 21 | * 22 | * http://www.7-zip.org/sdk.html 23 | * 24 | * The LzmaInputStream and LzmaOutputStream classes were inspired by the 25 | * work of Christopher League, although they are not derivative works. 26 | * 27 | * http://contrapunctus.net/league/haques/lzmajio/ 28 | */ 29 | 30 | package lzma.sdk.lz; 31 | 32 | import java.io.IOException; 33 | 34 | public class InWindow 35 | { 36 | byte[] _bufferBase; // pointer to buffer with data 37 | private java.io.InputStream _stream; 38 | private int _posLimit; // offset (from _buffer) of first byte when new block reading must be done 39 | private boolean _streamEndWasReached; // if (true) then _streamPos shows real end of stream 40 | 41 | private int _pointerToLastSafePosition; 42 | 43 | int _bufferOffset; 44 | 45 | private int _blockSize; // Size of Allocated memory block 46 | int _pos; // offset (from _buffer) of curent byte 47 | private int _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos 48 | private int _keepSizeAfter; // how many BYTEs must be kept buffer after _pos 49 | int _streamPos; // offset (from _buffer) of first not read byte from Stream 50 | 51 | void moveBlock() 52 | { 53 | int offset = _bufferOffset + _pos - _keepSizeBefore; 54 | // we need one additional byte, since movePos moves on 1 byte. 55 | if (offset > 0) 56 | { 57 | offset--; 58 | } 59 | 60 | int numBytes = _bufferOffset + _streamPos - offset; 61 | 62 | // check negative offset ???? 63 | System.arraycopy(_bufferBase, offset, _bufferBase, 0, numBytes); 64 | _bufferOffset -= offset; 65 | } 66 | 67 | void readBlock() throws IOException 68 | { 69 | if (_streamEndWasReached) 70 | { 71 | return; 72 | } 73 | while (true) 74 | { 75 | int size = (0 - _bufferOffset) + _blockSize - _streamPos; 76 | if (size == 0) 77 | { 78 | return; 79 | } 80 | int numReadBytes = _stream.read(_bufferBase, _bufferOffset + _streamPos, size); 81 | if (numReadBytes == -1) 82 | { 83 | _posLimit = _streamPos; 84 | int pointerToPostion = _bufferOffset + _posLimit; 85 | if (pointerToPostion > _pointerToLastSafePosition) 86 | { 87 | _posLimit = _pointerToLastSafePosition - _bufferOffset; 88 | } 89 | 90 | _streamEndWasReached = true; 91 | return; 92 | } 93 | _streamPos += numReadBytes; 94 | if (_streamPos >= _pos + _keepSizeAfter) 95 | { 96 | _posLimit = _streamPos - _keepSizeAfter; 97 | } 98 | } 99 | } 100 | 101 | void free() 102 | { 103 | _bufferBase = null; 104 | } 105 | 106 | void create(int keepSizeBefore, int keepSizeAfter, int keepSizeReserv) 107 | { 108 | _keepSizeBefore = keepSizeBefore; 109 | _keepSizeAfter = keepSizeAfter; 110 | int blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv; 111 | if (_bufferBase == null || _blockSize != blockSize) 112 | { 113 | free(); 114 | _blockSize = blockSize; 115 | _bufferBase = new byte[_blockSize]; 116 | } 117 | _pointerToLastSafePosition = _blockSize - keepSizeAfter; 118 | } 119 | 120 | public void setStream(java.io.InputStream stream) 121 | { 122 | _stream = stream; 123 | } 124 | 125 | public void releaseStream() 126 | { 127 | _stream = null; 128 | } 129 | 130 | void init() throws IOException 131 | { 132 | _bufferOffset = 0; 133 | _pos = 0; 134 | _streamPos = 0; 135 | _streamEndWasReached = false; 136 | readBlock(); 137 | } 138 | 139 | void movePos() throws IOException 140 | { 141 | _pos++; 142 | if (_pos > _posLimit) 143 | { 144 | int pointerToPostion = _bufferOffset + _pos; 145 | if (pointerToPostion > _pointerToLastSafePosition) 146 | { 147 | moveBlock(); 148 | } 149 | readBlock(); 150 | } 151 | } 152 | 153 | public byte getIndexByte(int index) 154 | { 155 | return _bufferBase[_bufferOffset + _pos + index]; 156 | } 157 | 158 | // index + limit have not to exceed _keepSizeAfter; 159 | public int getMatchLen(int index, int distance, int limit) 160 | { 161 | if (_streamEndWasReached) 162 | { 163 | if ((_pos + index) + limit > _streamPos) 164 | { 165 | limit = _streamPos - (_pos + index); 166 | } 167 | } 168 | distance++; 169 | // Byte *pby = _buffer + (size_t)_pos + index; 170 | int pby = _bufferOffset + _pos + index; 171 | 172 | int i; 173 | for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++) 174 | { 175 | } 176 | return i; 177 | } 178 | 179 | public int getNumAvailableBytes() 180 | { 181 | return _streamPos - _pos; 182 | } 183 | 184 | void reduceOffsets(int subValue) 185 | { 186 | _bufferOffset += subValue; 187 | _posLimit -= subValue; 188 | _pos -= subValue; 189 | _streamPos -= subValue; 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/test/java/lzma/streams/RoundtripTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011 Julien Ponge. All rights reserved. 3 | * 4 | * Portions Copyright (c) 2011 Tamas Cservenak. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package lzma.streams; 20 | 21 | import junit.framework.TestCase; 22 | import lzma.sdk.lzma.Decoder; 23 | import lzma.sdk.lzma.Encoder; 24 | import org.apache.commons.io.IOUtils; 25 | 26 | import java.io.*; 27 | 28 | import static org.apache.commons.io.FileUtils.contentEquals; 29 | 30 | public class RoundtripTest 31 | extends TestCase 32 | 33 | { 34 | public void testEncoderDecoder() 35 | throws IOException 36 | { 37 | System.out.println("Encoder/Decoder roundtrip (low-level API)"); 38 | final File srcDir = new File("target/test-classes"); 39 | 40 | performRoundtrip(new File(srcDir, "plaintext.txt")); 41 | performRoundtrip(new File(srcDir, "ajar.jar")); 42 | performRoundtrip(new File(srcDir, "doc.pdf")); 43 | } 44 | 45 | public void testStreamingEncoderDecoder() 46 | throws Exception 47 | { 48 | System.out.println("Stream roundtrip"); 49 | final File srcDir = new File("target/test-classes"); 50 | 51 | performStreamRoundtrip(new File(srcDir, "plaintext.txt")); 52 | performStreamRoundtrip(new File(srcDir, "ajar.jar")); 53 | performStreamRoundtrip(new File(srcDir, "doc.pdf")); 54 | } 55 | 56 | public void testAltStreamingEncoderDecoder() 57 | throws Exception 58 | { 59 | System.out.println("alt-Stream roundtrip"); 60 | final File srcDir = new File("target/test-classes"); 61 | 62 | performAltStreamRoundtrip(new File(srcDir, "plaintext.txt")); 63 | performAltStreamRoundtrip(new File(srcDir, "ajar.jar")); 64 | performAltStreamRoundtrip(new File(srcDir, "doc.pdf")); 65 | } 66 | 67 | public void performRoundtrip(final File sourceFile) 68 | throws IOException 69 | { 70 | final File compressedFile = new File(sourceFile.getParentFile(), sourceFile.getName() + ".coder.lzma"); 71 | final File decompressedFile = new File(sourceFile.getParentFile(), sourceFile.getName() + ".coder.unlzma"); 72 | 73 | InputStream in = null; 74 | OutputStream out = null; 75 | 76 | // compressing 77 | in = new BufferedInputStream(new FileInputStream(sourceFile)); 78 | out = new BufferedOutputStream(new FileOutputStream(compressedFile)); 79 | 80 | final Encoder encoder = new Encoder(); 81 | 82 | encoder.setDictionarySize(1 << 23); 83 | encoder.setEndMarkerMode(true); 84 | encoder.setMatchFinder(Encoder.EMatchFinderTypeBT4); 85 | encoder.setNumFastBytes(0x20); 86 | 87 | encoder.writeCoderProperties(out); 88 | long fileSize = sourceFile.length(); 89 | for (int i = 0; i < 8; i++) 90 | { 91 | out.write((int) (fileSize >>> (8 * i)) & 0xFF); 92 | } 93 | encoder.code(in, out, -1, -1, null); 94 | out.flush(); 95 | out.close(); 96 | in.close(); 97 | 98 | // decompressing 99 | in = new BufferedInputStream(new FileInputStream(compressedFile)); 100 | out = new BufferedOutputStream(new FileOutputStream(decompressedFile)); 101 | 102 | int propertiesSize = 5; 103 | byte[] properties = new byte[propertiesSize]; 104 | if (in.read(properties, 0, propertiesSize) != propertiesSize) 105 | { 106 | throw new IOException("input .lzma file is too short"); 107 | } 108 | Decoder decoder = new Decoder(); 109 | if (!decoder.setDecoderProperties(properties)) 110 | { 111 | throw new IOException("Incorrect stream properties"); 112 | } 113 | long outSize = 0; 114 | for (int i = 0; i < 8; i++) 115 | { 116 | int v = in.read(); 117 | if (v < 0) 118 | { 119 | throw new IOException("Can't read stream size"); 120 | } 121 | outSize |= ((long) v) << (8 * i); 122 | } 123 | if (!decoder.code(in, out, outSize)) 124 | { 125 | throw new IOException("Error in data stream"); 126 | } 127 | out.flush(); 128 | out.close(); 129 | in.close(); 130 | 131 | assertTrue("Source and uncompressed content does not equals!", contentEquals(sourceFile, decompressedFile)); 132 | assertFalse("Source and compressed content equals!", contentEquals(sourceFile, compressedFile)); 133 | } 134 | 135 | public void performStreamRoundtrip(final File sourceFile) 136 | throws IOException 137 | { 138 | final File compressedFile = new File(sourceFile.getParentFile(), sourceFile.getName() + ".stream.lzma"); 139 | final File decompressedFile = new File(sourceFile.getParentFile(), sourceFile.getName() + ".stream.unlzma"); 140 | 141 | InputStream in = null; 142 | OutputStream out = null; 143 | 144 | // testing with defaults 145 | in = new BufferedInputStream(new FileInputStream(sourceFile)); 146 | out = new LzmaOutputStream.Builder(new BufferedOutputStream(new FileOutputStream(compressedFile))).build(); 147 | 148 | IOUtils.copy(in, out); 149 | in.close(); 150 | out.close(); 151 | 152 | in = new LzmaInputStream(new BufferedInputStream(new FileInputStream(compressedFile)), new Decoder()); 153 | out = new BufferedOutputStream(new FileOutputStream(decompressedFile)); 154 | 155 | IOUtils.copy(in, out); 156 | in.close(); 157 | out.close(); 158 | 159 | assertTrue("Source and uncompressed content does not equals!", contentEquals(sourceFile, decompressedFile)); 160 | assertFalse("Source and compressed content equals!", contentEquals(sourceFile, compressedFile)); 161 | } 162 | 163 | public void performAltStreamRoundtrip(final File sourceFile) 164 | throws Exception 165 | { 166 | final File compressedFile = new File(sourceFile.getParentFile(), sourceFile.getName() + ".stream.lzma"); 167 | final File decompressedFile = new File(sourceFile.getParentFile(), sourceFile.getName() + ".stream.unlzma"); 168 | 169 | InputStream in = null; 170 | OutputStream out = null; 171 | 172 | // testing with defaults 173 | System.out.println(" o Stream compression"); 174 | in = new BufferedInputStream(new FileInputStream(sourceFile)); 175 | out = 176 | new LzmaOutputStream(new BufferedOutputStream(new FileOutputStream(compressedFile)), 177 | new LzmaEncoderWrapper.Builder().build()); 178 | 179 | IOUtils.copy(in, out); 180 | in.close(); 181 | out.flush(); 182 | out.close(); 183 | 184 | Thread.sleep(1000); 185 | 186 | System.out.println(" o Stream decompression"); 187 | in = 188 | new LzmaInputStream(new BufferedInputStream(new FileInputStream(compressedFile)), 189 | new Decoder()); 190 | out = new BufferedOutputStream(new FileOutputStream(decompressedFile)); 191 | 192 | IOUtils.copy(in, out); 193 | in.close(); 194 | out.close(); 195 | 196 | assertTrue("Source and uncompressed content does not equals!", contentEquals(sourceFile, decompressedFile)); 197 | assertFalse("Source and compressed content equals!", contentEquals(sourceFile, compressedFile)); 198 | } 199 | 200 | } 201 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /src/test/resources/plaintext.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /src/main/java/lzma/sdk/lz/BinTree.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Julien Ponge. All rights reserved. 3 | * 4 | * 5 | * http://julien.ponge.info/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * This work is based on the LZMA SDK by Igor Pavlov. 20 | * The LZMA SDK is placed under the public domain, and can be obtained from 21 | * 22 | * http://www.7-zip.org/sdk.html 23 | * 24 | * The LzmaInputStream and LzmaOutputStream classes were inspired by the 25 | * work of Christopher League, although they are not derivative works. 26 | * 27 | * http://contrapunctus.net/league/haques/lzmajio/ 28 | */ 29 | 30 | package lzma.sdk.lz; 31 | 32 | import java.io.IOException; 33 | import java.util.Arrays; 34 | 35 | 36 | public class BinTree extends InWindow 37 | { 38 | int _cyclicBufferPos; 39 | int _cyclicBufferSize = 0; 40 | int _matchMaxLen; 41 | 42 | int[] _son; 43 | int[] _hash; 44 | 45 | int _cutValue = 0xFF; 46 | int _hashMask; 47 | int _hashSizeSum = 0; 48 | 49 | private final boolean HASH_ARRAY; 50 | 51 | static final int kHash2Size = 1 << 10; 52 | static final int kHash3Size = 1 << 16; 53 | static final int kBT2HashSize = 1 << 16; 54 | static final int kStartMaxLen = 1; 55 | static final int kHash3Offset = kHash2Size; 56 | static final int kEmptyHashValue = 0; 57 | static final int kMaxValForNormalize = (1 << 30) - 1; 58 | 59 | int kNumHashDirectBytes = 0; 60 | int kMinMatchCheck = 4; 61 | int kFixHashSize = kHash2Size + kHash3Size; 62 | 63 | public BinTree(int numHashBytes) 64 | { 65 | HASH_ARRAY = (numHashBytes > 2); 66 | if (HASH_ARRAY) { 67 | kNumHashDirectBytes = 0; 68 | kMinMatchCheck = 4; 69 | kFixHashSize = kHash2Size + kHash3Size; 70 | } else { 71 | kNumHashDirectBytes = 2; 72 | kMinMatchCheck = 2 + 1; 73 | kFixHashSize = 0; 74 | } 75 | } 76 | 77 | public void init() throws IOException 78 | { 79 | super.init(); 80 | Arrays.fill(_hash, 0, _hashSizeSum, kEmptyHashValue); 81 | _cyclicBufferPos = 0; 82 | reduceOffsets(-1); 83 | } 84 | 85 | public void movePos() throws IOException 86 | { 87 | if (++_cyclicBufferPos >= _cyclicBufferSize) 88 | { 89 | _cyclicBufferPos = 0; 90 | } 91 | super.movePos(); 92 | if (_pos == kMaxValForNormalize) 93 | { 94 | normalize(); 95 | } 96 | } 97 | 98 | 99 | public boolean create(int historySize, int keepAddBufferBefore, 100 | int matchMaxLen, int keepAddBufferAfter) 101 | { 102 | if (historySize > kMaxValForNormalize - 256) 103 | { 104 | return false; 105 | } 106 | _cutValue = 16 + (matchMaxLen >> 1); 107 | 108 | int windowReservSize = (historySize + keepAddBufferBefore + 109 | matchMaxLen + keepAddBufferAfter) / 2 + 256; 110 | 111 | super.create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize); 112 | 113 | _matchMaxLen = matchMaxLen; 114 | 115 | int cyclicBufferSize = historySize + 1; 116 | if (_cyclicBufferSize != cyclicBufferSize) 117 | { 118 | _son = new int[(_cyclicBufferSize = cyclicBufferSize) * 2]; 119 | } 120 | 121 | int hs = kBT2HashSize; 122 | 123 | if (HASH_ARRAY) 124 | { 125 | hs = historySize - 1; 126 | hs |= (hs >> 1); 127 | hs |= (hs >> 2); 128 | hs |= (hs >> 4); 129 | hs |= (hs >> 8); 130 | hs >>= 1; 131 | hs |= 0xFFFF; 132 | if (hs > (1 << 24)) 133 | { 134 | hs >>= 1; 135 | } 136 | _hashMask = hs; 137 | hs++; 138 | hs += kFixHashSize; 139 | } 140 | if (hs != _hashSizeSum) 141 | { 142 | _hash = new int[_hashSizeSum = hs]; 143 | } 144 | return true; 145 | } 146 | 147 | public int getMatches(int[] distances) throws IOException 148 | { 149 | int lenLimit; 150 | if (_pos + _matchMaxLen <= _streamPos) 151 | { 152 | lenLimit = _matchMaxLen; 153 | } 154 | else 155 | { 156 | lenLimit = _streamPos - _pos; 157 | if (lenLimit < kMinMatchCheck) 158 | { 159 | movePos(); 160 | return 0; 161 | } 162 | } 163 | 164 | int offset = 0; 165 | int matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0; 166 | int cur = _bufferOffset + _pos; 167 | int maxLen = kStartMaxLen; // to avoid items for len < hashSize; 168 | int hashValue, hash2Value = 0, hash3Value = 0; 169 | 170 | if (HASH_ARRAY) 171 | { 172 | int temp = CrcTable[_bufferBase[cur] & 0xFF] ^ (_bufferBase[cur + 1] & 0xFF); 173 | hash2Value = temp & (kHash2Size - 1); 174 | temp ^= ((_bufferBase[cur + 2] & 0xFF) << 8); 175 | hash3Value = temp & (kHash3Size - 1); 176 | hashValue = (temp ^ (CrcTable[_bufferBase[cur + 3] & 0xFF] << 5)) & _hashMask; 177 | } 178 | else 179 | { 180 | hashValue = ((_bufferBase[cur] & 0xFF) ^ ((_bufferBase[cur + 1] & 0xFF) << 8)); 181 | } 182 | 183 | int curMatch = _hash[kFixHashSize + hashValue]; 184 | if (HASH_ARRAY) 185 | { 186 | int curMatch2 = _hash[hash2Value]; 187 | int curMatch3 = _hash[kHash3Offset + hash3Value]; 188 | _hash[hash2Value] = _pos; 189 | _hash[kHash3Offset + hash3Value] = _pos; 190 | if (curMatch2 > matchMinPos) 191 | { 192 | if (_bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur]) 193 | { 194 | distances[offset++] = maxLen = 2; 195 | distances[offset++] = _pos - curMatch2 - 1; 196 | } 197 | } 198 | if (curMatch3 > matchMinPos) 199 | { 200 | if (_bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur]) 201 | { 202 | if (curMatch3 == curMatch2) 203 | { 204 | offset -= 2; 205 | } 206 | distances[offset++] = maxLen = 3; 207 | distances[offset++] = _pos - curMatch3 - 1; 208 | curMatch2 = curMatch3; 209 | } 210 | } 211 | if (offset != 0 && curMatch2 == curMatch) 212 | { 213 | offset -= 2; 214 | maxLen = kStartMaxLen; 215 | } 216 | } 217 | 218 | _hash[kFixHashSize + hashValue] = _pos; 219 | 220 | int ptr0 = (_cyclicBufferPos << 1) + 1; 221 | int ptr1 = (_cyclicBufferPos << 1); 222 | 223 | int len0, len1; 224 | len0 = len1 = kNumHashDirectBytes; 225 | 226 | if (kNumHashDirectBytes != 0) 227 | { 228 | if (curMatch > matchMinPos) 229 | { 230 | if (_bufferBase[_bufferOffset + curMatch + kNumHashDirectBytes] != 231 | _bufferBase[cur + kNumHashDirectBytes]) 232 | { 233 | distances[offset++] = maxLen = kNumHashDirectBytes; 234 | distances[offset++] = _pos - curMatch - 1; 235 | } 236 | } 237 | } 238 | 239 | int count = _cutValue; 240 | 241 | while (true) 242 | { 243 | if (curMatch <= matchMinPos || count-- == 0) 244 | { 245 | _son[ptr0] = _son[ptr1] = kEmptyHashValue; 246 | break; 247 | } 248 | int delta = _pos - curMatch; 249 | int cyclicPos = ((delta <= _cyclicBufferPos) ? 250 | (_cyclicBufferPos - delta) : 251 | (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1; 252 | 253 | int pby1 = _bufferOffset + curMatch; 254 | int len = Math.min(len0, len1); 255 | if (_bufferBase[pby1 + len] == _bufferBase[cur + len]) 256 | { 257 | while (++len != lenLimit) 258 | { 259 | if (_bufferBase[pby1 + len] != _bufferBase[cur + len]) 260 | { 261 | break; 262 | } 263 | } 264 | if (maxLen < len) 265 | { 266 | distances[offset++] = maxLen = len; 267 | distances[offset++] = delta - 1; 268 | if (len == lenLimit) 269 | { 270 | _son[ptr1] = _son[cyclicPos]; 271 | _son[ptr0] = _son[cyclicPos + 1]; 272 | break; 273 | } 274 | } 275 | } 276 | if ((_bufferBase[pby1 + len] & 0xFF) < (_bufferBase[cur + len] & 0xFF)) 277 | { 278 | _son[ptr1] = curMatch; 279 | ptr1 = cyclicPos + 1; 280 | curMatch = _son[ptr1]; 281 | len1 = len; 282 | } 283 | else 284 | { 285 | _son[ptr0] = curMatch; 286 | ptr0 = cyclicPos; 287 | curMatch = _son[ptr0]; 288 | len0 = len; 289 | } 290 | } 291 | movePos(); 292 | return offset; 293 | } 294 | 295 | public void skip(int num) throws IOException 296 | { 297 | do 298 | { 299 | int lenLimit; 300 | if (_pos + _matchMaxLen <= _streamPos) 301 | { 302 | lenLimit = _matchMaxLen; 303 | } 304 | else 305 | { 306 | lenLimit = _streamPos - _pos; 307 | if (lenLimit < kMinMatchCheck) 308 | { 309 | movePos(); 310 | continue; 311 | } 312 | } 313 | 314 | int matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0; 315 | int cur = _bufferOffset + _pos; 316 | 317 | int hashValue; 318 | 319 | if (HASH_ARRAY) 320 | { 321 | int temp = CrcTable[_bufferBase[cur] & 0xFF] ^ (_bufferBase[cur + 1] & 0xFF); 322 | int hash2Value = temp & (kHash2Size - 1); 323 | _hash[hash2Value] = _pos; 324 | temp ^= ((_bufferBase[cur + 2] & 0xFF) << 8); 325 | int hash3Value = temp & (kHash3Size - 1); 326 | _hash[kHash3Offset + hash3Value] = _pos; 327 | hashValue = (temp ^ (CrcTable[_bufferBase[cur + 3] & 0xFF] << 5)) & _hashMask; 328 | } 329 | else 330 | { 331 | hashValue = ((_bufferBase[cur] & 0xFF) ^ ((_bufferBase[cur + 1] & 0xFF) << 8)); 332 | } 333 | 334 | int curMatch = _hash[kFixHashSize + hashValue]; 335 | _hash[kFixHashSize + hashValue] = _pos; 336 | 337 | int ptr0 = (_cyclicBufferPos << 1) + 1; 338 | int ptr1 = (_cyclicBufferPos << 1); 339 | 340 | int len0, len1; 341 | len0 = len1 = kNumHashDirectBytes; 342 | 343 | int count = _cutValue; 344 | while (true) 345 | { 346 | if (curMatch <= matchMinPos || count-- == 0) 347 | { 348 | _son[ptr0] = _son[ptr1] = kEmptyHashValue; 349 | break; 350 | } 351 | 352 | int delta = _pos - curMatch; 353 | int cyclicPos = ((delta <= _cyclicBufferPos) ? 354 | (_cyclicBufferPos - delta) : 355 | (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1; 356 | 357 | int pby1 = _bufferOffset + curMatch; 358 | int len = Math.min(len0, len1); 359 | if (_bufferBase[pby1 + len] == _bufferBase[cur + len]) 360 | { 361 | while (++len != lenLimit) 362 | { 363 | if (_bufferBase[pby1 + len] != _bufferBase[cur + len]) 364 | { 365 | break; 366 | } 367 | } 368 | if (len == lenLimit) 369 | { 370 | _son[ptr1] = _son[cyclicPos]; 371 | _son[ptr0] = _son[cyclicPos + 1]; 372 | break; 373 | } 374 | } 375 | if ((_bufferBase[pby1 + len] & 0xFF) < (_bufferBase[cur + len] & 0xFF)) 376 | { 377 | _son[ptr1] = curMatch; 378 | ptr1 = cyclicPos + 1; 379 | curMatch = _son[ptr1]; 380 | len1 = len; 381 | } 382 | else 383 | { 384 | _son[ptr0] = curMatch; 385 | ptr0 = cyclicPos; 386 | curMatch = _son[ptr0]; 387 | len0 = len; 388 | } 389 | } 390 | movePos(); 391 | } 392 | while (--num != 0); 393 | } 394 | 395 | void normalizeLinks(int[] items, int numItems, int subValue) 396 | { 397 | for (int i = 0; i < numItems; i++) 398 | { 399 | int value = items[i]; 400 | if (value <= subValue) 401 | { 402 | value = kEmptyHashValue; 403 | } 404 | else 405 | { 406 | value -= subValue; 407 | } 408 | items[i] = value; 409 | } 410 | } 411 | 412 | void normalize() 413 | { 414 | int subValue = _pos - _cyclicBufferSize; 415 | normalizeLinks(_son, _cyclicBufferSize * 2, subValue); 416 | normalizeLinks(_hash, _hashSizeSum, subValue); 417 | reduceOffsets(subValue); 418 | } 419 | 420 | private static final int[] CrcTable = new int[256]; 421 | 422 | static 423 | { 424 | for (int i = 0; i < 256; i++) 425 | { 426 | int r = i; 427 | for (int j = 0; j < 8; j++) 428 | { 429 | if ((r & 1) != 0) 430 | { 431 | r = (r >>> 1) ^ 0xEDB88320; 432 | } 433 | else 434 | { 435 | r >>>= 1; 436 | } 437 | } 438 | CrcTable[i] = r; 439 | } 440 | } 441 | } 442 | -------------------------------------------------------------------------------- /src/main/java/lzma/sdk/lzma/Decoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Julien Ponge. All rights reserved. 3 | * 4 | * 5 | * http://julien.ponge.info/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * This work is based on the LZMA SDK by Igor Pavlov. 20 | * The LZMA SDK is placed under the public domain, and can be obtained from 21 | * 22 | * http://www.7-zip.org/sdk.html 23 | * 24 | * The LzmaInputStream and LzmaOutputStream classes were inspired by the 25 | * work of Christopher League, although they are not derivative works. 26 | * 27 | * http://contrapunctus.net/league/haques/lzmajio/ 28 | */ 29 | 30 | package lzma.sdk.lzma; 31 | 32 | import lzma.sdk.lz.OutWindow; 33 | import lzma.sdk.rangecoder.BitTreeDecoder; 34 | 35 | import java.io.IOException; 36 | 37 | public class Decoder 38 | { 39 | class LenDecoder 40 | { 41 | final short[] m_Choice = new short[2]; 42 | final BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax]; 43 | final BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax]; 44 | final BitTreeDecoder m_HighCoder = new BitTreeDecoder(Base.kNumHighLenBits); 45 | int m_NumPosStates = 0; 46 | 47 | public void create(int numPosStates) 48 | { 49 | for (; m_NumPosStates < numPosStates; m_NumPosStates++) 50 | { 51 | m_LowCoder[m_NumPosStates] = new BitTreeDecoder(Base.kNumLowLenBits); 52 | m_MidCoder[m_NumPosStates] = new BitTreeDecoder(Base.kNumMidLenBits); 53 | } 54 | } 55 | 56 | public void init() 57 | { 58 | lzma.sdk.rangecoder.Decoder.initBitModels(m_Choice); 59 | for (int posState = 0; posState < m_NumPosStates; posState++) 60 | { 61 | m_LowCoder[posState].init(); 62 | m_MidCoder[posState].init(); 63 | } 64 | m_HighCoder.init(); 65 | } 66 | 67 | public int decode(lzma.sdk.rangecoder.Decoder rangeDecoder, int posState) throws IOException 68 | { 69 | if (rangeDecoder.decodeBit(m_Choice, 0) == 0) 70 | { 71 | return m_LowCoder[posState].decode(rangeDecoder); 72 | } 73 | int symbol = Base.kNumLowLenSymbols; 74 | if (rangeDecoder.decodeBit(m_Choice, 1) == 0) 75 | { 76 | symbol += m_MidCoder[posState].decode(rangeDecoder); 77 | } 78 | else 79 | { 80 | symbol += Base.kNumMidLenSymbols + m_HighCoder.decode(rangeDecoder); 81 | } 82 | return symbol; 83 | } 84 | } 85 | 86 | class LiteralDecoder 87 | { 88 | class Decoder2 89 | { 90 | final short[] m_Decoders = new short[0x300]; 91 | 92 | public void init() 93 | { 94 | lzma.sdk.rangecoder.Decoder.initBitModels(m_Decoders); 95 | } 96 | 97 | public byte decodeNormal(lzma.sdk.rangecoder.Decoder rangeDecoder) throws IOException 98 | { 99 | int symbol = 1; 100 | do 101 | { 102 | symbol = (symbol << 1) | rangeDecoder.decodeBit(m_Decoders, symbol); 103 | } 104 | while (symbol < 0x100); 105 | return (byte) symbol; 106 | } 107 | 108 | public byte decodeWithMatchByte(lzma.sdk.rangecoder.Decoder rangeDecoder, byte matchByte) throws IOException 109 | { 110 | int symbol = 1; 111 | do 112 | { 113 | int matchBit = (matchByte >> 7) & 1; 114 | matchByte <<= 1; 115 | int bit = rangeDecoder.decodeBit(m_Decoders, ((1 + matchBit) << 8) + symbol); 116 | symbol = (symbol << 1) | bit; 117 | if (matchBit != bit) 118 | { 119 | while (symbol < 0x100) 120 | { 121 | symbol = (symbol << 1) | rangeDecoder.decodeBit(m_Decoders, symbol); 122 | } 123 | break; 124 | } 125 | } 126 | while (symbol < 0x100); 127 | return (byte) symbol; 128 | } 129 | } 130 | 131 | Decoder2[] m_Coders; 132 | int m_NumPrevBits; 133 | int m_NumPosBits; 134 | int m_PosMask; 135 | 136 | public void create(int numPosBits, int numPrevBits) 137 | { 138 | if (m_Coders != null && m_NumPrevBits == numPrevBits && m_NumPosBits == numPosBits) 139 | { 140 | return; 141 | } 142 | m_NumPosBits = numPosBits; 143 | m_PosMask = (1 << numPosBits) - 1; 144 | m_NumPrevBits = numPrevBits; 145 | int numStates = 1 << (m_NumPrevBits + m_NumPosBits); 146 | m_Coders = new Decoder2[numStates]; 147 | for (int i = 0; i < numStates; i++) 148 | { 149 | m_Coders[i] = new Decoder2(); 150 | } 151 | } 152 | 153 | public void init() 154 | { 155 | int numStates = 1 << (m_NumPrevBits + m_NumPosBits); 156 | for (int i = 0; i < numStates; i++) 157 | { 158 | m_Coders[i].init(); 159 | } 160 | } 161 | 162 | Decoder2 getDecoder(int pos, byte prevByte) 163 | { 164 | return m_Coders[((pos & m_PosMask) << m_NumPrevBits) + ((prevByte & 0xFF) >>> (8 - m_NumPrevBits))]; 165 | } 166 | } 167 | 168 | private final OutWindow m_OutWindow = new OutWindow(); 169 | private final lzma.sdk.rangecoder.Decoder m_RangeDecoder = new lzma.sdk.rangecoder.Decoder(); 170 | 171 | private final short[] m_IsMatchDecoders = new short[Base.kNumStates << Base.kNumPosStatesBitsMax]; 172 | private final short[] m_IsRepDecoders = new short[Base.kNumStates]; 173 | private final short[] m_IsRepG0Decoders = new short[Base.kNumStates]; 174 | private final short[] m_IsRepG1Decoders = new short[Base.kNumStates]; 175 | private final short[] m_IsRepG2Decoders = new short[Base.kNumStates]; 176 | private final short[] m_IsRep0LongDecoders = new short[Base.kNumStates << Base.kNumPosStatesBitsMax]; 177 | 178 | private final BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates]; 179 | private final short[] m_PosDecoders = new short[Base.kNumFullDistances - Base.kEndPosModelIndex]; 180 | 181 | private final BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(Base.kNumAlignBits); 182 | 183 | private final LenDecoder m_LenDecoder = new LenDecoder(); 184 | private final LenDecoder m_RepLenDecoder = new LenDecoder(); 185 | 186 | private final LiteralDecoder m_LiteralDecoder = new LiteralDecoder(); 187 | 188 | private int m_DictionarySize = -1; 189 | private int m_DictionarySizeCheck = -1; 190 | 191 | private int m_PosStateMask; 192 | 193 | public Decoder() 194 | { 195 | for (int i = 0; i < Base.kNumLenToPosStates; i++) 196 | { 197 | m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits); 198 | } 199 | } 200 | 201 | boolean setDictionarySize(int dictionarySize) 202 | { 203 | if (dictionarySize < 0) 204 | { 205 | return false; 206 | } 207 | if (m_DictionarySize != dictionarySize) 208 | { 209 | m_DictionarySize = dictionarySize; 210 | m_DictionarySizeCheck = Math.max(m_DictionarySize, 1); 211 | m_OutWindow.create(Math.max(m_DictionarySizeCheck, (1 << 12))); 212 | } 213 | return true; 214 | } 215 | 216 | boolean setLcLpPb(int lc, int lp, int pb) 217 | { 218 | if (lc > Base.kNumLitContextBitsMax || lp > 4 || pb > Base.kNumPosStatesBitsMax) 219 | { 220 | return false; 221 | } 222 | m_LiteralDecoder.create(lp, lc); 223 | int numPosStates = 1 << pb; 224 | m_LenDecoder.create(numPosStates); 225 | m_RepLenDecoder.create(numPosStates); 226 | m_PosStateMask = numPosStates - 1; 227 | return true; 228 | } 229 | 230 | void init() throws IOException 231 | { 232 | m_OutWindow.init(false); 233 | 234 | lzma.sdk.rangecoder.Decoder.initBitModels(m_IsMatchDecoders); 235 | lzma.sdk.rangecoder.Decoder.initBitModels(m_IsRep0LongDecoders); 236 | lzma.sdk.rangecoder.Decoder.initBitModels(m_IsRepDecoders); 237 | lzma.sdk.rangecoder.Decoder.initBitModels(m_IsRepG0Decoders); 238 | lzma.sdk.rangecoder.Decoder.initBitModels(m_IsRepG1Decoders); 239 | lzma.sdk.rangecoder.Decoder.initBitModels(m_IsRepG2Decoders); 240 | lzma.sdk.rangecoder.Decoder.initBitModels(m_PosDecoders); 241 | 242 | m_LiteralDecoder.init(); 243 | int i; 244 | for (i = 0; i < Base.kNumLenToPosStates; i++) 245 | { 246 | m_PosSlotDecoder[i].init(); 247 | } 248 | m_LenDecoder.init(); 249 | m_RepLenDecoder.init(); 250 | m_PosAlignDecoder.init(); 251 | m_RangeDecoder.init(); 252 | } 253 | 254 | public boolean code(java.io.InputStream inStream, java.io.OutputStream outStream, 255 | long outSize) throws IOException 256 | { 257 | m_RangeDecoder.setStream(inStream); 258 | m_OutWindow.setStream(outStream); 259 | init(); 260 | 261 | int state = Base.stateInit(); 262 | int rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0; 263 | 264 | long nowPos64 = 0; 265 | byte prevByte = 0; 266 | while (outSize < 0 || nowPos64 < outSize) 267 | { 268 | int posState = (int) nowPos64 & m_PosStateMask; 269 | if (m_RangeDecoder.decodeBit(m_IsMatchDecoders, (state << Base.kNumPosStatesBitsMax) + posState) == 0) 270 | { 271 | LiteralDecoder.Decoder2 decoder2 = m_LiteralDecoder.getDecoder((int) nowPos64, prevByte); 272 | if (!Base.stateIsCharState(state)) 273 | { 274 | prevByte = decoder2.decodeWithMatchByte(m_RangeDecoder, m_OutWindow.getByte(rep0)); 275 | } 276 | else 277 | { 278 | prevByte = decoder2.decodeNormal(m_RangeDecoder); 279 | } 280 | m_OutWindow.putByte(prevByte); 281 | state = Base.stateUpdateChar(state); 282 | nowPos64++; 283 | } 284 | else 285 | { 286 | int len; 287 | if (m_RangeDecoder.decodeBit(m_IsRepDecoders, state) == 1) 288 | { 289 | len = 0; 290 | if (m_RangeDecoder.decodeBit(m_IsRepG0Decoders, state) == 0) 291 | { 292 | if (m_RangeDecoder.decodeBit(m_IsRep0LongDecoders, (state << Base.kNumPosStatesBitsMax) + posState) == 0) 293 | { 294 | state = Base.stateUpdateShortRep(state); 295 | len = 1; 296 | } 297 | } 298 | else 299 | { 300 | int distance; 301 | if (m_RangeDecoder.decodeBit(m_IsRepG1Decoders, state) == 0) 302 | { 303 | distance = rep1; 304 | } 305 | else 306 | { 307 | if (m_RangeDecoder.decodeBit(m_IsRepG2Decoders, state) == 0) 308 | { 309 | distance = rep2; 310 | } 311 | else 312 | { 313 | distance = rep3; 314 | rep3 = rep2; 315 | } 316 | rep2 = rep1; 317 | } 318 | rep1 = rep0; 319 | rep0 = distance; 320 | } 321 | if (len == 0) 322 | { 323 | len = m_RepLenDecoder.decode(m_RangeDecoder, posState) + Base.kMatchMinLen; 324 | state = Base.stateUpdateRep(state); 325 | } 326 | } 327 | else 328 | { 329 | rep3 = rep2; 330 | rep2 = rep1; 331 | rep1 = rep0; 332 | len = Base.kMatchMinLen + m_LenDecoder.decode(m_RangeDecoder, posState); 333 | state = Base.stateUpdateMatch(state); 334 | int posSlot = m_PosSlotDecoder[Base.getLenToPosState(len)].decode(m_RangeDecoder); 335 | if (posSlot >= Base.kStartPosModelIndex) 336 | { 337 | int numDirectBits = (posSlot >> 1) - 1; 338 | rep0 = ((2 | (posSlot & 1)) << numDirectBits); 339 | if (posSlot < Base.kEndPosModelIndex) 340 | { 341 | rep0 += BitTreeDecoder.reverseDecode(m_PosDecoders, 342 | rep0 - posSlot - 1, m_RangeDecoder, numDirectBits); 343 | } 344 | else 345 | { 346 | rep0 += (m_RangeDecoder.decodeDirectBits( 347 | numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits); 348 | rep0 += m_PosAlignDecoder.reverseDecode(m_RangeDecoder); 349 | if (rep0 < 0) 350 | { 351 | if (rep0 == -1) 352 | { 353 | break; 354 | } 355 | return false; 356 | } 357 | } 358 | } 359 | else 360 | { 361 | rep0 = posSlot; 362 | } 363 | } 364 | if (rep0 >= nowPos64 || rep0 >= m_DictionarySizeCheck) 365 | { 366 | // m_OutWindow.flush(); 367 | return false; 368 | } 369 | m_OutWindow.copyBlock(rep0, len); 370 | nowPos64 += len; 371 | prevByte = m_OutWindow.getByte(0); 372 | } 373 | } 374 | m_OutWindow.flush(); 375 | m_OutWindow.releaseStream(); 376 | m_RangeDecoder.releaseStream(); 377 | return true; 378 | } 379 | 380 | public boolean setDecoderProperties(byte[] properties) 381 | { 382 | if (properties.length < 5) 383 | { 384 | return false; 385 | } 386 | int val = properties[0] & 0xFF; 387 | int lc = val % 9; 388 | int remainder = val / 9; 389 | int lp = remainder % 5; 390 | int pb = remainder / 5; 391 | int dictionarySize = 0; 392 | for (int i = 0; i < 4; i++) 393 | { 394 | dictionarySize += ((int) (properties[1 + i]) & 0xFF) << (i * 8); 395 | } 396 | return setLcLpPb(lc, lp, pb) && setDictionarySize(dictionarySize); 397 | } 398 | } 399 | -------------------------------------------------------------------------------- /src/main/java/lzma/sdk/lzma/Encoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 Julien Ponge. All rights reserved. 3 | * 4 | * 5 | * http://julien.ponge.info/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * 19 | * This work is based on the LZMA SDK by Igor Pavlov. 20 | * The LZMA SDK is placed under the public domain, and can be obtained from 21 | * 22 | * http://www.7-zip.org/sdk.html 23 | * 24 | * The LzmaInputStream and LzmaOutputStream classes were inspired by the 25 | * work of Christopher League, although they are not derivative works. 26 | * 27 | * http://contrapunctus.net/league/haques/lzmajio/ 28 | */ 29 | 30 | package lzma.sdk.lzma; 31 | 32 | import lzma.sdk.ICodeProgress; 33 | import lzma.sdk.rangecoder.BitTreeEncoder; 34 | 35 | import java.io.IOException; 36 | 37 | public class Encoder 38 | { 39 | public static final int EMatchFinderTypeBT2 = 0; 40 | public static final int EMatchFinderTypeBT4 = 1; 41 | 42 | 43 | static final int kIfinityPrice = 0xFFFFFFF; 44 | 45 | static byte[] g_FastPos = new byte[1 << 11]; 46 | 47 | static 48 | { 49 | int kFastSlots = 22; 50 | int c = 2; 51 | g_FastPos[0] = 0; 52 | g_FastPos[1] = 1; 53 | for (int slotFast = 2; slotFast < kFastSlots; slotFast++) 54 | { 55 | int k = (1 << ((slotFast >> 1) - 1)); 56 | for (int j = 0; j < k; j++, c++) 57 | { 58 | g_FastPos[c] = (byte) slotFast; 59 | } 60 | } 61 | } 62 | 63 | static int getPosSlot(int pos) 64 | { 65 | if (pos < (1 << 11)) 66 | { 67 | return g_FastPos[pos]; 68 | } 69 | if (pos < (1 << 21)) 70 | { 71 | return (g_FastPos[pos >> 10] + 20); 72 | } 73 | return (g_FastPos[pos >> 20] + 40); 74 | } 75 | 76 | static int getPosSlot2(int pos) 77 | { 78 | if (pos < (1 << 17)) 79 | { 80 | return (g_FastPos[pos >> 6] + 12); 81 | } 82 | if (pos < (1 << 27)) 83 | { 84 | return (g_FastPos[pos >> 16] + 32); 85 | } 86 | return (g_FastPos[pos >> 26] + 52); 87 | } 88 | 89 | int _state = Base.stateInit(); 90 | byte _previousByte; 91 | int[] _repDistances = new int[Base.kNumRepDistances]; 92 | 93 | void baseInit() 94 | { 95 | _state = Base.stateInit(); 96 | _previousByte = 0; 97 | for (int i = 0; i < Base.kNumRepDistances; i++) 98 | { 99 | _repDistances[i] = 0; 100 | } 101 | } 102 | 103 | static final int kDefaultDictionaryLogSize = 22; 104 | static final int kNumFastBytesDefault = 0x20; 105 | 106 | class LiteralEncoder 107 | { 108 | class Encoder2 109 | { 110 | short[] m_Encoders = new short[0x300]; 111 | 112 | public void init() 113 | { 114 | lzma.sdk.rangecoder.Encoder.initBitModels(m_Encoders); 115 | } 116 | 117 | 118 | public void encode(lzma.sdk.rangecoder.Encoder rangeEncoder, byte symbol) throws IOException 119 | { 120 | int context = 1; 121 | for (int i = 7; i >= 0; i--) 122 | { 123 | int bit = ((symbol >> i) & 1); 124 | rangeEncoder.encode(m_Encoders, context, bit); 125 | context = (context << 1) | bit; 126 | } 127 | } 128 | 129 | public void encodeMatched(lzma.sdk.rangecoder.Encoder rangeEncoder, byte matchByte, byte symbol) throws IOException 130 | { 131 | int context = 1; 132 | boolean same = true; 133 | for (int i = 7; i >= 0; i--) 134 | { 135 | int bit = ((symbol >> i) & 1); 136 | int state = context; 137 | if (same) 138 | { 139 | int matchBit = ((matchByte >> i) & 1); 140 | state += ((1 + matchBit) << 8); 141 | same = (matchBit == bit); 142 | } 143 | rangeEncoder.encode(m_Encoders, state, bit); 144 | context = (context << 1) | bit; 145 | } 146 | } 147 | 148 | public int getPrice(boolean matchMode, byte matchByte, byte symbol) 149 | { 150 | int price = 0; 151 | int context = 1; 152 | int i = 7; 153 | if (matchMode) 154 | { 155 | for (; i >= 0; i--) 156 | { 157 | int matchBit = (matchByte >> i) & 1; 158 | int bit = (symbol >> i) & 1; 159 | price += lzma.sdk.rangecoder.Encoder.getPrice(m_Encoders[((1 + matchBit) << 8) + context], bit); 160 | context = (context << 1) | bit; 161 | if (matchBit != bit) 162 | { 163 | i--; 164 | break; 165 | } 166 | } 167 | } 168 | for (; i >= 0; i--) 169 | { 170 | int bit = (symbol >> i) & 1; 171 | price += lzma.sdk.rangecoder.Encoder.getPrice(m_Encoders[context], bit); 172 | context = (context << 1) | bit; 173 | } 174 | return price; 175 | } 176 | } 177 | 178 | Encoder2[] m_Coders; 179 | int m_NumPrevBits; 180 | int m_NumPosBits; 181 | int m_PosMask; 182 | 183 | public void create(int numPosBits, int numPrevBits) 184 | { 185 | if (m_Coders != null && m_NumPrevBits == numPrevBits && m_NumPosBits == numPosBits) 186 | { 187 | return; 188 | } 189 | m_NumPosBits = numPosBits; 190 | m_PosMask = (1 << numPosBits) - 1; 191 | m_NumPrevBits = numPrevBits; 192 | int numStates = 1 << (m_NumPrevBits + m_NumPosBits); 193 | m_Coders = new Encoder2[numStates]; 194 | for (int i = 0; i < numStates; i++) 195 | { 196 | m_Coders[i] = new Encoder2(); 197 | } 198 | } 199 | 200 | public void init() 201 | { 202 | int numStates = 1 << (m_NumPrevBits + m_NumPosBits); 203 | for (int i = 0; i < numStates; i++) 204 | { 205 | m_Coders[i].init(); 206 | } 207 | } 208 | 209 | public Encoder2 getSubCoder(int pos, byte prevByte) 210 | { 211 | return m_Coders[((pos & m_PosMask) << m_NumPrevBits) + ((prevByte & 0xFF) >>> (8 - m_NumPrevBits))]; 212 | } 213 | } 214 | 215 | class LenEncoder 216 | { 217 | short[] _choice = new short[2]; 218 | BitTreeEncoder[] _lowCoder = new BitTreeEncoder[Base.kNumPosStatesEncodingMax]; 219 | BitTreeEncoder[] _midCoder = new BitTreeEncoder[Base.kNumPosStatesEncodingMax]; 220 | BitTreeEncoder _highCoder = new BitTreeEncoder(Base.kNumHighLenBits); 221 | 222 | 223 | public LenEncoder() 224 | { 225 | for (int posState = 0; posState < Base.kNumPosStatesEncodingMax; posState++) 226 | { 227 | _lowCoder[posState] = new BitTreeEncoder(Base.kNumLowLenBits); 228 | _midCoder[posState] = new BitTreeEncoder(Base.kNumMidLenBits); 229 | } 230 | } 231 | 232 | public void init(int numPosStates) 233 | { 234 | lzma.sdk.rangecoder.Encoder.initBitModels(_choice); 235 | 236 | for (int posState = 0; posState < numPosStates; posState++) 237 | { 238 | _lowCoder[posState].init(); 239 | _midCoder[posState].init(); 240 | } 241 | _highCoder.init(); 242 | } 243 | 244 | public void encode(lzma.sdk.rangecoder.Encoder rangeEncoder, int symbol, int posState) throws IOException 245 | { 246 | if (symbol < Base.kNumLowLenSymbols) 247 | { 248 | rangeEncoder.encode(_choice, 0, 0); 249 | _lowCoder[posState].encode(rangeEncoder, symbol); 250 | } 251 | else 252 | { 253 | symbol -= Base.kNumLowLenSymbols; 254 | rangeEncoder.encode(_choice, 0, 1); 255 | if (symbol < Base.kNumMidLenSymbols) 256 | { 257 | rangeEncoder.encode(_choice, 1, 0); 258 | _midCoder[posState].encode(rangeEncoder, symbol); 259 | } 260 | else 261 | { 262 | rangeEncoder.encode(_choice, 1, 1); 263 | _highCoder.encode(rangeEncoder, symbol - Base.kNumMidLenSymbols); 264 | } 265 | } 266 | } 267 | 268 | public void setPrices(int posState, int numSymbols, int[] prices, int st) 269 | { 270 | int a0 = lzma.sdk.rangecoder.Encoder.getPrice0(_choice[0]); 271 | int a1 = lzma.sdk.rangecoder.Encoder.getPrice1(_choice[0]); 272 | int b0 = a1 + lzma.sdk.rangecoder.Encoder.getPrice0(_choice[1]); 273 | int b1 = a1 + lzma.sdk.rangecoder.Encoder.getPrice1(_choice[1]); 274 | int i; 275 | for (i = 0; i < Base.kNumLowLenSymbols; i++) 276 | { 277 | if (i >= numSymbols) 278 | { 279 | return; 280 | } 281 | prices[st + i] = a0 + _lowCoder[posState].getPrice(i); 282 | } 283 | for (; i < Base.kNumLowLenSymbols + Base.kNumMidLenSymbols; i++) 284 | { 285 | if (i >= numSymbols) 286 | { 287 | return; 288 | } 289 | prices[st + i] = b0 + _midCoder[posState].getPrice(i - Base.kNumLowLenSymbols); 290 | } 291 | for (; i < numSymbols; i++) 292 | { 293 | prices[st + i] = b1 + _highCoder.getPrice(i - Base.kNumLowLenSymbols - Base.kNumMidLenSymbols); 294 | } 295 | } 296 | } 297 | 298 | class LenPriceTableEncoder extends LenEncoder 299 | { 300 | int[] _prices = new int[Base.kNumLenSymbols << Base.kNumPosStatesBitsEncodingMax]; 301 | int _tableSize; 302 | int[] _counters = new int[Base.kNumPosStatesEncodingMax]; 303 | 304 | public void setTableSize(int tableSize) 305 | { 306 | _tableSize = tableSize; 307 | } 308 | 309 | public int getPrice(int symbol, int posState) 310 | { 311 | return _prices[posState * Base.kNumLenSymbols + symbol]; 312 | } 313 | 314 | void updateTable(int posState) 315 | { 316 | setPrices(posState, _tableSize, _prices, posState * Base.kNumLenSymbols); 317 | _counters[posState] = _tableSize; 318 | } 319 | 320 | public void updateTables(int numPosStates) 321 | { 322 | for (int posState = 0; posState < numPosStates; posState++) 323 | { 324 | updateTable(posState); 325 | } 326 | } 327 | 328 | public void encode(lzma.sdk.rangecoder.Encoder rangeEncoder, int symbol, int posState) throws IOException 329 | { 330 | super.encode(rangeEncoder, symbol, posState); 331 | if (--_counters[posState] == 0) 332 | { 333 | updateTable(posState); 334 | } 335 | } 336 | } 337 | 338 | static final int kNumOpts = 1 << 12; 339 | 340 | class Optimal 341 | { 342 | public int State; 343 | 344 | public boolean Prev1IsChar; 345 | public boolean Prev2; 346 | 347 | public int PosPrev2; 348 | public int BackPrev2; 349 | 350 | public int Price; 351 | public int PosPrev; 352 | public int BackPrev; 353 | 354 | public int Backs0; 355 | public int Backs1; 356 | public int Backs2; 357 | public int Backs3; 358 | 359 | public void makeAsChar() 360 | { 361 | BackPrev = -1; 362 | Prev1IsChar = false; 363 | } 364 | 365 | public void makeAsShortRep() 366 | { 367 | BackPrev = 0; 368 | Prev1IsChar = false; 369 | } 370 | 371 | public boolean isShortRep() 372 | { 373 | return (BackPrev == 0); 374 | } 375 | } 376 | 377 | Optimal[] _optimum = new Optimal[kNumOpts]; 378 | lzma.sdk.lz.BinTree _matchFinder = null; 379 | lzma.sdk.rangecoder.Encoder _rangeEncoder = new lzma.sdk.rangecoder.Encoder(); 380 | 381 | short[] _isMatch = new short[Base.kNumStates << Base.kNumPosStatesBitsMax]; 382 | short[] _isRep = new short[Base.kNumStates]; 383 | short[] _isRepG0 = new short[Base.kNumStates]; 384 | short[] _isRepG1 = new short[Base.kNumStates]; 385 | short[] _isRepG2 = new short[Base.kNumStates]; 386 | short[] _isRep0Long = new short[Base.kNumStates << Base.kNumPosStatesBitsMax]; 387 | 388 | BitTreeEncoder[] _posSlotEncoder = new BitTreeEncoder[Base.kNumLenToPosStates]; // kNumPosSlotBits 389 | 390 | short[] _posEncoders = new short[Base.kNumFullDistances - Base.kEndPosModelIndex]; 391 | BitTreeEncoder _posAlignEncoder = new BitTreeEncoder(Base.kNumAlignBits); 392 | 393 | LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder(); 394 | LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder(); 395 | 396 | LiteralEncoder _literalEncoder = new LiteralEncoder(); 397 | 398 | int[] _matchDistances = new int[Base.kMatchMaxLen * 2 + 2]; 399 | 400 | int _numFastBytes = kNumFastBytesDefault; 401 | int _longestMatchLength; 402 | int _numDistancePairs; 403 | 404 | int _additionalOffset; 405 | 406 | int _optimumEndIndex; 407 | int _optimumCurrentIndex; 408 | 409 | boolean _longestMatchWasFound; 410 | 411 | int[] _posSlotPrices = new int[1 << (Base.kNumPosSlotBits + Base.kNumLenToPosStatesBits)]; 412 | int[] _distancesPrices = new int[Base.kNumFullDistances << Base.kNumLenToPosStatesBits]; 413 | int[] _alignPrices = new int[Base.kAlignTableSize]; 414 | int _alignPriceCount; 415 | 416 | int _distTableSize = (kDefaultDictionaryLogSize * 2); 417 | 418 | int _posStateBits = 2; 419 | int _posStateMask = (4 - 1); 420 | int _numLiteralPosStateBits = 0; 421 | int _numLiteralContextBits = 3; 422 | 423 | int _dictionarySize = (1 << kDefaultDictionaryLogSize); 424 | int _dictionarySizePrev = -1; 425 | int _numFastBytesPrev = -1; 426 | 427 | long nowPos64; 428 | boolean _finished; 429 | java.io.InputStream _inStream; 430 | 431 | int _matchFinderType = EMatchFinderTypeBT4; 432 | boolean _writeEndMark = false; 433 | 434 | boolean _needReleaseMFStream = false; 435 | 436 | void create() 437 | { 438 | if (_matchFinder == null) 439 | { 440 | int numHashBytes = 4; 441 | if (_matchFinderType == EMatchFinderTypeBT2) 442 | { 443 | numHashBytes = 2; 444 | } 445 | lzma.sdk.lz.BinTree bt = new lzma.sdk.lz.BinTree(numHashBytes); 446 | _matchFinder = bt; 447 | } 448 | _literalEncoder.create(_numLiteralPosStateBits, _numLiteralContextBits); 449 | 450 | if (_dictionarySize == _dictionarySizePrev && _numFastBytesPrev == _numFastBytes) 451 | { 452 | return; 453 | } 454 | _matchFinder.create(_dictionarySize, kNumOpts, _numFastBytes, Base.kMatchMaxLen + 1); 455 | _dictionarySizePrev = _dictionarySize; 456 | _numFastBytesPrev = _numFastBytes; 457 | } 458 | 459 | public Encoder() 460 | { 461 | for (int i = 0; i < kNumOpts; i++) 462 | { 463 | _optimum[i] = new Optimal(); 464 | } 465 | for (int i = 0; i < Base.kNumLenToPosStates; i++) 466 | { 467 | _posSlotEncoder[i] = new BitTreeEncoder(Base.kNumPosSlotBits); 468 | } 469 | } 470 | 471 | void init() 472 | { 473 | baseInit(); 474 | _rangeEncoder.init(); 475 | 476 | lzma.sdk.rangecoder.Encoder.initBitModels(_isMatch); 477 | lzma.sdk.rangecoder.Encoder.initBitModels(_isRep0Long); 478 | lzma.sdk.rangecoder.Encoder.initBitModels(_isRep); 479 | lzma.sdk.rangecoder.Encoder.initBitModels(_isRepG0); 480 | lzma.sdk.rangecoder.Encoder.initBitModels(_isRepG1); 481 | lzma.sdk.rangecoder.Encoder.initBitModels(_isRepG2); 482 | lzma.sdk.rangecoder.Encoder.initBitModels(_posEncoders); 483 | 484 | 485 | _literalEncoder.init(); 486 | for (int i = 0; i < Base.kNumLenToPosStates; i++) 487 | { 488 | _posSlotEncoder[i].init(); 489 | } 490 | 491 | 492 | _lenEncoder.init(1 << _posStateBits); 493 | _repMatchLenEncoder.init(1 << _posStateBits); 494 | 495 | _posAlignEncoder.init(); 496 | 497 | _longestMatchWasFound = false; 498 | _optimumEndIndex = 0; 499 | _optimumCurrentIndex = 0; 500 | _additionalOffset = 0; 501 | } 502 | 503 | int readMatchDistances() throws java.io.IOException 504 | { 505 | int lenRes = 0; 506 | _numDistancePairs = _matchFinder.getMatches(_matchDistances); 507 | if (_numDistancePairs > 0) 508 | { 509 | lenRes = _matchDistances[_numDistancePairs - 2]; 510 | if (lenRes == _numFastBytes) 511 | { 512 | lenRes += _matchFinder.getMatchLen(lenRes - 1, _matchDistances[_numDistancePairs - 1], 513 | Base.kMatchMaxLen - lenRes); 514 | } 515 | } 516 | _additionalOffset++; 517 | return lenRes; 518 | } 519 | 520 | void movePos(int num) throws java.io.IOException 521 | { 522 | if (num > 0) 523 | { 524 | _matchFinder.skip(num); 525 | _additionalOffset += num; 526 | } 527 | } 528 | 529 | int getRepLen1Price(int state, int posState) 530 | { 531 | return lzma.sdk.rangecoder.Encoder.getPrice0(_isRepG0[state]) + 532 | lzma.sdk.rangecoder.Encoder.getPrice0(_isRep0Long[(state << Base.kNumPosStatesBitsMax) + posState]); 533 | } 534 | 535 | int getPureRepPrice(int repIndex, int state, int posState) 536 | { 537 | int price; 538 | if (repIndex == 0) 539 | { 540 | price = lzma.sdk.rangecoder.Encoder.getPrice0(_isRepG0[state]); 541 | price += lzma.sdk.rangecoder.Encoder.getPrice1(_isRep0Long[(state << Base.kNumPosStatesBitsMax) + posState]); 542 | } 543 | else 544 | { 545 | price = lzma.sdk.rangecoder.Encoder.getPrice1(_isRepG0[state]); 546 | if (repIndex == 1) 547 | { 548 | price += lzma.sdk.rangecoder.Encoder.getPrice0(_isRepG1[state]); 549 | } 550 | else 551 | { 552 | price += lzma.sdk.rangecoder.Encoder.getPrice1(_isRepG1[state]); 553 | price += lzma.sdk.rangecoder.Encoder.getPrice(_isRepG2[state], repIndex - 2); 554 | } 555 | } 556 | return price; 557 | } 558 | 559 | int getRepPrice(int repIndex, int len, int state, int posState) 560 | { 561 | int price = _repMatchLenEncoder.getPrice(len - Base.kMatchMinLen, posState); 562 | return price + getPureRepPrice(repIndex, state, posState); 563 | } 564 | 565 | int getPosLenPrice(int pos, int len, int posState) 566 | { 567 | int price; 568 | int lenToPosState = Base.getLenToPosState(len); 569 | if (pos < Base.kNumFullDistances) 570 | { 571 | price = _distancesPrices[(lenToPosState * Base.kNumFullDistances) + pos]; 572 | } 573 | else 574 | { 575 | price = _posSlotPrices[(lenToPosState << Base.kNumPosSlotBits) + getPosSlot2(pos)] + 576 | _alignPrices[pos & Base.kAlignMask]; 577 | } 578 | return price + _lenEncoder.getPrice(len - Base.kMatchMinLen, posState); 579 | } 580 | 581 | int backward(int cur) 582 | { 583 | _optimumEndIndex = cur; 584 | int posMem = _optimum[cur].PosPrev; 585 | int backMem = _optimum[cur].BackPrev; 586 | do 587 | { 588 | if (_optimum[cur].Prev1IsChar) 589 | { 590 | _optimum[posMem].makeAsChar(); 591 | _optimum[posMem].PosPrev = posMem - 1; 592 | if (_optimum[cur].Prev2) 593 | { 594 | _optimum[posMem - 1].Prev1IsChar = false; 595 | _optimum[posMem - 1].PosPrev = _optimum[cur].PosPrev2; 596 | _optimum[posMem - 1].BackPrev = _optimum[cur].BackPrev2; 597 | } 598 | } 599 | int posPrev = posMem; 600 | int backCur = backMem; 601 | 602 | backMem = _optimum[posPrev].BackPrev; 603 | posMem = _optimum[posPrev].PosPrev; 604 | 605 | _optimum[posPrev].BackPrev = backCur; 606 | _optimum[posPrev].PosPrev = cur; 607 | cur = posPrev; 608 | } 609 | while (cur > 0); 610 | backRes = _optimum[0].BackPrev; 611 | _optimumCurrentIndex = _optimum[0].PosPrev; 612 | return _optimumCurrentIndex; 613 | } 614 | 615 | int[] reps = new int[Base.kNumRepDistances]; 616 | int[] repLens = new int[Base.kNumRepDistances]; 617 | int backRes; 618 | 619 | int getOptimum(int position) throws IOException 620 | { 621 | if (_optimumEndIndex != _optimumCurrentIndex) 622 | { 623 | int lenRes = _optimum[_optimumCurrentIndex].PosPrev - _optimumCurrentIndex; 624 | backRes = _optimum[_optimumCurrentIndex].BackPrev; 625 | _optimumCurrentIndex = _optimum[_optimumCurrentIndex].PosPrev; 626 | return lenRes; 627 | } 628 | _optimumCurrentIndex = _optimumEndIndex = 0; 629 | 630 | int lenMain, numDistancePairs; 631 | if (!_longestMatchWasFound) 632 | { 633 | lenMain = readMatchDistances(); 634 | } 635 | else 636 | { 637 | lenMain = _longestMatchLength; 638 | _longestMatchWasFound = false; 639 | } 640 | numDistancePairs = _numDistancePairs; 641 | 642 | int numAvailableBytes = _matchFinder.getNumAvailableBytes() + 1; 643 | if (numAvailableBytes < 2) 644 | { 645 | backRes = -1; 646 | return 1; 647 | } 648 | if (numAvailableBytes > Base.kMatchMaxLen) 649 | { 650 | numAvailableBytes = Base.kMatchMaxLen; 651 | } 652 | 653 | int repMaxIndex = 0; 654 | int i; 655 | for (i = 0; i < Base.kNumRepDistances; i++) 656 | { 657 | reps[i] = _repDistances[i]; 658 | repLens[i] = _matchFinder.getMatchLen(0 - 1, reps[i], Base.kMatchMaxLen); 659 | if (repLens[i] > repLens[repMaxIndex]) 660 | { 661 | repMaxIndex = i; 662 | } 663 | } 664 | if (repLens[repMaxIndex] >= _numFastBytes) 665 | { 666 | backRes = repMaxIndex; 667 | int lenRes = repLens[repMaxIndex]; 668 | movePos(lenRes - 1); 669 | return lenRes; 670 | } 671 | 672 | if (lenMain >= _numFastBytes) 673 | { 674 | backRes = _matchDistances[numDistancePairs - 1] + Base.kNumRepDistances; 675 | movePos(lenMain - 1); 676 | return lenMain; 677 | } 678 | 679 | byte currentByte = _matchFinder.getIndexByte(0 - 1); 680 | byte matchByte = _matchFinder.getIndexByte(0 - _repDistances[0] - 1 - 1); 681 | 682 | if (lenMain < 2 && currentByte != matchByte && repLens[repMaxIndex] < 2) 683 | { 684 | backRes = -1; 685 | return 1; 686 | } 687 | 688 | _optimum[0].State = _state; 689 | 690 | int posState = (position & _posStateMask); 691 | 692 | _optimum[1].Price = lzma.sdk.rangecoder.Encoder.getPrice0(_isMatch[(_state << Base.kNumPosStatesBitsMax) + posState]) + 693 | _literalEncoder.getSubCoder(position, _previousByte).getPrice(!Base.stateIsCharState(_state), matchByte, currentByte); 694 | _optimum[1].makeAsChar(); 695 | 696 | int matchPrice = lzma.sdk.rangecoder.Encoder.getPrice1(_isMatch[(_state << Base.kNumPosStatesBitsMax) + posState]); 697 | int repMatchPrice = matchPrice + lzma.sdk.rangecoder.Encoder.getPrice1(_isRep[_state]); 698 | 699 | if (matchByte == currentByte) 700 | { 701 | int shortRepPrice = repMatchPrice + getRepLen1Price(_state, posState); 702 | if (shortRepPrice < _optimum[1].Price) 703 | { 704 | _optimum[1].Price = shortRepPrice; 705 | _optimum[1].makeAsShortRep(); 706 | } 707 | } 708 | 709 | int lenEnd = ((lenMain >= repLens[repMaxIndex]) ? lenMain : repLens[repMaxIndex]); 710 | 711 | if (lenEnd < 2) 712 | { 713 | backRes = _optimum[1].BackPrev; 714 | return 1; 715 | } 716 | 717 | _optimum[1].PosPrev = 0; 718 | 719 | _optimum[0].Backs0 = reps[0]; 720 | _optimum[0].Backs1 = reps[1]; 721 | _optimum[0].Backs2 = reps[2]; 722 | _optimum[0].Backs3 = reps[3]; 723 | 724 | int len = lenEnd; 725 | do 726 | { 727 | _optimum[len--].Price = kIfinityPrice; 728 | } 729 | while (len >= 2); 730 | 731 | for (i = 0; i < Base.kNumRepDistances; i++) 732 | { 733 | int repLen = repLens[i]; 734 | if (repLen < 2) 735 | { 736 | continue; 737 | } 738 | int price = repMatchPrice + getPureRepPrice(i, _state, posState); 739 | do 740 | { 741 | int curAndLenPrice = price + _repMatchLenEncoder.getPrice(repLen - 2, posState); 742 | Optimal optimum = _optimum[repLen]; 743 | if (curAndLenPrice < optimum.Price) 744 | { 745 | optimum.Price = curAndLenPrice; 746 | optimum.PosPrev = 0; 747 | optimum.BackPrev = i; 748 | optimum.Prev1IsChar = false; 749 | } 750 | } 751 | while (--repLen >= 2); 752 | } 753 | 754 | int normalMatchPrice = matchPrice + lzma.sdk.rangecoder.Encoder.getPrice0(_isRep[_state]); 755 | 756 | len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2); 757 | if (len <= lenMain) 758 | { 759 | int offs = 0; 760 | while (len > _matchDistances[offs]) 761 | { 762 | offs += 2; 763 | } 764 | for (; ; len++) 765 | { 766 | int distance = _matchDistances[offs + 1]; 767 | int curAndLenPrice = normalMatchPrice + getPosLenPrice(distance, len, posState); 768 | Optimal optimum = _optimum[len]; 769 | if (curAndLenPrice < optimum.Price) 770 | { 771 | optimum.Price = curAndLenPrice; 772 | optimum.PosPrev = 0; 773 | optimum.BackPrev = distance + Base.kNumRepDistances; 774 | optimum.Prev1IsChar = false; 775 | } 776 | if (len == _matchDistances[offs]) 777 | { 778 | offs += 2; 779 | if (offs == numDistancePairs) 780 | { 781 | break; 782 | } 783 | } 784 | } 785 | } 786 | 787 | int cur = 0; 788 | 789 | while (true) 790 | { 791 | cur++; 792 | if (cur == lenEnd) 793 | { 794 | return backward(cur); 795 | } 796 | int newLen = readMatchDistances(); 797 | numDistancePairs = _numDistancePairs; 798 | if (newLen >= _numFastBytes) 799 | { 800 | 801 | _longestMatchLength = newLen; 802 | _longestMatchWasFound = true; 803 | return backward(cur); 804 | } 805 | position++; 806 | int posPrev = _optimum[cur].PosPrev; 807 | int state; 808 | if (_optimum[cur].Prev1IsChar) 809 | { 810 | posPrev--; 811 | if (_optimum[cur].Prev2) 812 | { 813 | state = _optimum[_optimum[cur].PosPrev2].State; 814 | if (_optimum[cur].BackPrev2 < Base.kNumRepDistances) 815 | { 816 | state = Base.stateUpdateRep(state); 817 | } 818 | else 819 | { 820 | state = Base.stateUpdateMatch(state); 821 | } 822 | } 823 | else 824 | { 825 | state = _optimum[posPrev].State; 826 | } 827 | state = Base.stateUpdateChar(state); 828 | } 829 | else 830 | { 831 | state = _optimum[posPrev].State; 832 | } 833 | if (posPrev == cur - 1) 834 | { 835 | if (_optimum[cur].isShortRep()) 836 | { 837 | state = Base.stateUpdateShortRep(state); 838 | } 839 | else 840 | { 841 | state = Base.stateUpdateChar(state); 842 | } 843 | } 844 | else 845 | { 846 | int pos; 847 | if (_optimum[cur].Prev1IsChar && _optimum[cur].Prev2) 848 | { 849 | posPrev = _optimum[cur].PosPrev2; 850 | pos = _optimum[cur].BackPrev2; 851 | state = Base.stateUpdateRep(state); 852 | } 853 | else 854 | { 855 | pos = _optimum[cur].BackPrev; 856 | if (pos < Base.kNumRepDistances) 857 | { 858 | state = Base.stateUpdateRep(state); 859 | } 860 | else 861 | { 862 | state = Base.stateUpdateMatch(state); 863 | } 864 | } 865 | Optimal opt = _optimum[posPrev]; 866 | if (pos < Base.kNumRepDistances) 867 | { 868 | if (pos == 0) 869 | { 870 | reps[0] = opt.Backs0; 871 | reps[1] = opt.Backs1; 872 | reps[2] = opt.Backs2; 873 | reps[3] = opt.Backs3; 874 | } 875 | else if (pos == 1) 876 | { 877 | reps[0] = opt.Backs1; 878 | reps[1] = opt.Backs0; 879 | reps[2] = opt.Backs2; 880 | reps[3] = opt.Backs3; 881 | } 882 | else if (pos == 2) 883 | { 884 | reps[0] = opt.Backs2; 885 | reps[1] = opt.Backs0; 886 | reps[2] = opt.Backs1; 887 | reps[3] = opt.Backs3; 888 | } 889 | else 890 | { 891 | reps[0] = opt.Backs3; 892 | reps[1] = opt.Backs0; 893 | reps[2] = opt.Backs1; 894 | reps[3] = opt.Backs2; 895 | } 896 | } 897 | else 898 | { 899 | reps[0] = (pos - Base.kNumRepDistances); 900 | reps[1] = opt.Backs0; 901 | reps[2] = opt.Backs1; 902 | reps[3] = opt.Backs2; 903 | } 904 | } 905 | _optimum[cur].State = state; 906 | _optimum[cur].Backs0 = reps[0]; 907 | _optimum[cur].Backs1 = reps[1]; 908 | _optimum[cur].Backs2 = reps[2]; 909 | _optimum[cur].Backs3 = reps[3]; 910 | int curPrice = _optimum[cur].Price; 911 | 912 | currentByte = _matchFinder.getIndexByte(0 - 1); 913 | matchByte = _matchFinder.getIndexByte(0 - reps[0] - 1 - 1); 914 | 915 | posState = (position & _posStateMask); 916 | 917 | int curAnd1Price = curPrice + 918 | lzma.sdk.rangecoder.Encoder.getPrice0(_isMatch[(state << Base.kNumPosStatesBitsMax) + posState]) + 919 | _literalEncoder.getSubCoder(position, _matchFinder.getIndexByte(0 - 2)). 920 | getPrice(!Base.stateIsCharState(state), matchByte, currentByte); 921 | 922 | Optimal nextOptimum = _optimum[cur + 1]; 923 | 924 | boolean nextIsChar = false; 925 | if (curAnd1Price < nextOptimum.Price) 926 | { 927 | nextOptimum.Price = curAnd1Price; 928 | nextOptimum.PosPrev = cur; 929 | nextOptimum.makeAsChar(); 930 | nextIsChar = true; 931 | } 932 | 933 | matchPrice = curPrice + lzma.sdk.rangecoder.Encoder.getPrice1(_isMatch[(state << Base.kNumPosStatesBitsMax) + posState]); 934 | repMatchPrice = matchPrice + lzma.sdk.rangecoder.Encoder.getPrice1(_isRep[state]); 935 | 936 | if (matchByte == currentByte && 937 | !(nextOptimum.PosPrev < cur && nextOptimum.BackPrev == 0)) 938 | { 939 | int shortRepPrice = repMatchPrice + getRepLen1Price(state, posState); 940 | if (shortRepPrice <= nextOptimum.Price) 941 | { 942 | nextOptimum.Price = shortRepPrice; 943 | nextOptimum.PosPrev = cur; 944 | nextOptimum.makeAsShortRep(); 945 | nextIsChar = true; 946 | } 947 | } 948 | 949 | int numAvailableBytesFull = _matchFinder.getNumAvailableBytes() + 1; 950 | numAvailableBytesFull = Math.min(kNumOpts - 1 - cur, numAvailableBytesFull); 951 | numAvailableBytes = numAvailableBytesFull; 952 | 953 | if (numAvailableBytes < 2) 954 | { 955 | continue; 956 | } 957 | if (numAvailableBytes > _numFastBytes) 958 | { 959 | numAvailableBytes = _numFastBytes; 960 | } 961 | if (!nextIsChar && matchByte != currentByte) 962 | { 963 | // try Literal + rep0 964 | int t = Math.min(numAvailableBytesFull - 1, _numFastBytes); 965 | int lenTest2 = _matchFinder.getMatchLen(0, reps[0], t); 966 | if (lenTest2 >= 2) 967 | { 968 | int state2 = Base.stateUpdateChar(state); 969 | 970 | int posStateNext = (position + 1) & _posStateMask; 971 | int nextRepMatchPrice = curAnd1Price + 972 | lzma.sdk.rangecoder.Encoder.getPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]) + 973 | lzma.sdk.rangecoder.Encoder.getPrice1(_isRep[state2]); 974 | { 975 | int offset = cur + 1 + lenTest2; 976 | while (lenEnd < offset) 977 | { 978 | _optimum[++lenEnd].Price = kIfinityPrice; 979 | } 980 | int curAndLenPrice = nextRepMatchPrice + getRepPrice( 981 | 0, lenTest2, state2, posStateNext); 982 | Optimal optimum = _optimum[offset]; 983 | if (curAndLenPrice < optimum.Price) 984 | { 985 | optimum.Price = curAndLenPrice; 986 | optimum.PosPrev = cur + 1; 987 | optimum.BackPrev = 0; 988 | optimum.Prev1IsChar = true; 989 | optimum.Prev2 = false; 990 | } 991 | } 992 | } 993 | } 994 | 995 | int startLen = 2; // speed optimization 996 | 997 | for (int repIndex = 0; repIndex < Base.kNumRepDistances; repIndex++) 998 | { 999 | int lenTest = _matchFinder.getMatchLen(0 - 1, reps[repIndex], numAvailableBytes); 1000 | if (lenTest < 2) 1001 | { 1002 | continue; 1003 | } 1004 | int lenTestTemp = lenTest; 1005 | do 1006 | { 1007 | while (lenEnd < cur + lenTest) 1008 | { 1009 | _optimum[++lenEnd].Price = kIfinityPrice; 1010 | } 1011 | int curAndLenPrice = repMatchPrice + getRepPrice(repIndex, lenTest, state, posState); 1012 | Optimal optimum = _optimum[cur + lenTest]; 1013 | if (curAndLenPrice < optimum.Price) 1014 | { 1015 | optimum.Price = curAndLenPrice; 1016 | optimum.PosPrev = cur; 1017 | optimum.BackPrev = repIndex; 1018 | optimum.Prev1IsChar = false; 1019 | } 1020 | } 1021 | while (--lenTest >= 2); 1022 | lenTest = lenTestTemp; 1023 | 1024 | if (repIndex == 0) 1025 | { 1026 | startLen = lenTest + 1; 1027 | } 1028 | 1029 | // if (_maxMode) 1030 | if (lenTest < numAvailableBytesFull) 1031 | { 1032 | int t = Math.min(numAvailableBytesFull - 1 - lenTest, _numFastBytes); 1033 | int lenTest2 = _matchFinder.getMatchLen(lenTest, reps[repIndex], t); 1034 | if (lenTest2 >= 2) 1035 | { 1036 | int state2 = Base.stateUpdateRep(state); 1037 | 1038 | int posStateNext = (position + lenTest) & _posStateMask; 1039 | int curAndLenCharPrice = 1040 | repMatchPrice + getRepPrice(repIndex, lenTest, state, posState) + 1041 | lzma.sdk.rangecoder.Encoder.getPrice0(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]) + 1042 | _literalEncoder.getSubCoder(position + lenTest, 1043 | _matchFinder.getIndexByte(lenTest - 1 - 1)).getPrice(true, 1044 | _matchFinder.getIndexByte(lenTest - 1 - (reps[repIndex] + 1)), 1045 | _matchFinder.getIndexByte(lenTest - 1)); 1046 | state2 = Base.stateUpdateChar(state2); 1047 | posStateNext = (position + lenTest + 1) & _posStateMask; 1048 | int nextMatchPrice = curAndLenCharPrice + lzma.sdk.rangecoder.Encoder.getPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]); 1049 | int nextRepMatchPrice = nextMatchPrice + lzma.sdk.rangecoder.Encoder.getPrice1(_isRep[state2]); 1050 | 1051 | // for(; lenTest2 >= 2; lenTest2--) 1052 | { 1053 | int offset = lenTest + 1 + lenTest2; 1054 | while (lenEnd < cur + offset) 1055 | { 1056 | _optimum[++lenEnd].Price = kIfinityPrice; 1057 | } 1058 | int curAndLenPrice = nextRepMatchPrice + getRepPrice(0, lenTest2, state2, posStateNext); 1059 | Optimal optimum = _optimum[cur + offset]; 1060 | if (curAndLenPrice < optimum.Price) 1061 | { 1062 | optimum.Price = curAndLenPrice; 1063 | optimum.PosPrev = cur + lenTest + 1; 1064 | optimum.BackPrev = 0; 1065 | optimum.Prev1IsChar = true; 1066 | optimum.Prev2 = true; 1067 | optimum.PosPrev2 = cur; 1068 | optimum.BackPrev2 = repIndex; 1069 | } 1070 | } 1071 | } 1072 | } 1073 | } 1074 | 1075 | if (newLen > numAvailableBytes) 1076 | { 1077 | newLen = numAvailableBytes; 1078 | for (numDistancePairs = 0; newLen > _matchDistances[numDistancePairs]; numDistancePairs += 2) 1079 | { 1080 | } 1081 | _matchDistances[numDistancePairs] = newLen; 1082 | numDistancePairs += 2; 1083 | } 1084 | if (newLen >= startLen) 1085 | { 1086 | normalMatchPrice = matchPrice + lzma.sdk.rangecoder.Encoder.getPrice0(_isRep[state]); 1087 | while (lenEnd < cur + newLen) 1088 | { 1089 | _optimum[++lenEnd].Price = kIfinityPrice; 1090 | } 1091 | 1092 | int offs = 0; 1093 | while (startLen > _matchDistances[offs]) 1094 | { 1095 | offs += 2; 1096 | } 1097 | 1098 | for (int lenTest = startLen; ; lenTest++) 1099 | { 1100 | int curBack = _matchDistances[offs + 1]; 1101 | int curAndLenPrice = normalMatchPrice + getPosLenPrice(curBack, lenTest, posState); 1102 | Optimal optimum = _optimum[cur + lenTest]; 1103 | if (curAndLenPrice < optimum.Price) 1104 | { 1105 | optimum.Price = curAndLenPrice; 1106 | optimum.PosPrev = cur; 1107 | optimum.BackPrev = curBack + Base.kNumRepDistances; 1108 | optimum.Prev1IsChar = false; 1109 | } 1110 | 1111 | if (lenTest == _matchDistances[offs]) 1112 | { 1113 | if (lenTest < numAvailableBytesFull) 1114 | { 1115 | int t = Math.min(numAvailableBytesFull - 1 - lenTest, _numFastBytes); 1116 | int lenTest2 = _matchFinder.getMatchLen(lenTest, curBack, t); 1117 | if (lenTest2 >= 2) 1118 | { 1119 | int state2 = Base.stateUpdateMatch(state); 1120 | 1121 | int posStateNext = (position + lenTest) & _posStateMask; 1122 | int curAndLenCharPrice = curAndLenPrice + 1123 | lzma.sdk.rangecoder.Encoder.getPrice0(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]) + 1124 | _literalEncoder.getSubCoder(position + lenTest, 1125 | _matchFinder.getIndexByte(lenTest - 1 - 1)). 1126 | getPrice(true, 1127 | _matchFinder.getIndexByte(lenTest - (curBack + 1) - 1), 1128 | _matchFinder.getIndexByte(lenTest - 1)); 1129 | state2 = Base.stateUpdateChar(state2); 1130 | posStateNext = (position + lenTest + 1) & _posStateMask; 1131 | int nextMatchPrice = curAndLenCharPrice + lzma.sdk.rangecoder.Encoder.getPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]); 1132 | int nextRepMatchPrice = nextMatchPrice + lzma.sdk.rangecoder.Encoder.getPrice1(_isRep[state2]); 1133 | 1134 | int offset = lenTest + 1 + lenTest2; 1135 | while (lenEnd < cur + offset) 1136 | { 1137 | _optimum[++lenEnd].Price = kIfinityPrice; 1138 | } 1139 | curAndLenPrice = nextRepMatchPrice + getRepPrice(0, lenTest2, state2, posStateNext); 1140 | optimum = _optimum[cur + offset]; 1141 | if (curAndLenPrice < optimum.Price) 1142 | { 1143 | optimum.Price = curAndLenPrice; 1144 | optimum.PosPrev = cur + lenTest + 1; 1145 | optimum.BackPrev = 0; 1146 | optimum.Prev1IsChar = true; 1147 | optimum.Prev2 = true; 1148 | optimum.PosPrev2 = cur; 1149 | optimum.BackPrev2 = curBack + Base.kNumRepDistances; 1150 | } 1151 | } 1152 | } 1153 | offs += 2; 1154 | if (offs == numDistancePairs) 1155 | { 1156 | break; 1157 | } 1158 | } 1159 | } 1160 | } 1161 | } 1162 | } 1163 | 1164 | void writeEndMarker(int posState) throws IOException 1165 | { 1166 | if (!_writeEndMark) 1167 | { 1168 | return; 1169 | } 1170 | 1171 | _rangeEncoder.encode(_isMatch, (_state << Base.kNumPosStatesBitsMax) + posState, 1); 1172 | _rangeEncoder.encode(_isRep, _state, 0); 1173 | _state = Base.stateUpdateMatch(_state); 1174 | int len = Base.kMatchMinLen; 1175 | _lenEncoder.encode(_rangeEncoder, len - Base.kMatchMinLen, posState); 1176 | int posSlot = (1 << Base.kNumPosSlotBits) - 1; 1177 | int lenToPosState = Base.getLenToPosState(len); 1178 | _posSlotEncoder[lenToPosState].encode(_rangeEncoder, posSlot); 1179 | int footerBits = 30; 1180 | int posReduced = (1 << footerBits) - 1; 1181 | _rangeEncoder.encodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits); 1182 | _posAlignEncoder.reverseEncode(_rangeEncoder, posReduced & Base.kAlignMask); 1183 | } 1184 | 1185 | void flush(int nowPos) throws IOException 1186 | { 1187 | releaseMFStream(); 1188 | writeEndMarker(nowPos & _posStateMask); 1189 | _rangeEncoder.flushData(); 1190 | _rangeEncoder.flushStream(); 1191 | } 1192 | 1193 | public void codeOneBlock(long[] inSize, long[] outSize, boolean[] finished) throws IOException 1194 | { 1195 | inSize[0] = 0; 1196 | outSize[0] = 0; 1197 | finished[0] = true; 1198 | 1199 | if (_inStream != null) 1200 | { 1201 | _matchFinder.setStream(_inStream); 1202 | _matchFinder.init(); 1203 | _needReleaseMFStream = true; 1204 | _inStream = null; 1205 | } 1206 | 1207 | if (_finished) 1208 | { 1209 | return; 1210 | } 1211 | _finished = true; 1212 | 1213 | 1214 | long progressPosValuePrev = nowPos64; 1215 | if (nowPos64 == 0) 1216 | { 1217 | if (_matchFinder.getNumAvailableBytes() == 0) 1218 | { 1219 | flush((int) nowPos64); 1220 | return; 1221 | } 1222 | 1223 | readMatchDistances(); 1224 | int posState = (int) (nowPos64) & _posStateMask; 1225 | _rangeEncoder.encode(_isMatch, (_state << Base.kNumPosStatesBitsMax) + posState, 0); 1226 | _state = Base.stateUpdateChar(_state); 1227 | byte curByte = _matchFinder.getIndexByte(0 - _additionalOffset); 1228 | _literalEncoder.getSubCoder((int) (nowPos64), _previousByte).encode(_rangeEncoder, curByte); 1229 | _previousByte = curByte; 1230 | _additionalOffset--; 1231 | nowPos64++; 1232 | } 1233 | if (_matchFinder.getNumAvailableBytes() == 0) 1234 | { 1235 | flush((int) nowPos64); 1236 | return; 1237 | } 1238 | while (true) 1239 | { 1240 | 1241 | int len = getOptimum((int) nowPos64); 1242 | int pos = backRes; 1243 | int posState = ((int) nowPos64) & _posStateMask; 1244 | int complexState = (_state << Base.kNumPosStatesBitsMax) + posState; 1245 | if (len == 1 && pos == -1) 1246 | { 1247 | _rangeEncoder.encode(_isMatch, complexState, 0); 1248 | byte curByte = _matchFinder.getIndexByte(0 - _additionalOffset); 1249 | LiteralEncoder.Encoder2 subCoder = _literalEncoder.getSubCoder((int) nowPos64, _previousByte); 1250 | if (!Base.stateIsCharState(_state)) 1251 | { 1252 | byte matchByte = _matchFinder.getIndexByte(0 - _repDistances[0] - 1 - _additionalOffset); 1253 | subCoder.encodeMatched(_rangeEncoder, matchByte, curByte); 1254 | } 1255 | else 1256 | { 1257 | subCoder.encode(_rangeEncoder, curByte); 1258 | } 1259 | _previousByte = curByte; 1260 | _state = Base.stateUpdateChar(_state); 1261 | } 1262 | else 1263 | { 1264 | _rangeEncoder.encode(_isMatch, complexState, 1); 1265 | if (pos < Base.kNumRepDistances) 1266 | { 1267 | _rangeEncoder.encode(_isRep, _state, 1); 1268 | if (pos == 0) 1269 | { 1270 | _rangeEncoder.encode(_isRepG0, _state, 0); 1271 | if (len == 1) 1272 | { 1273 | _rangeEncoder.encode(_isRep0Long, complexState, 0); 1274 | } 1275 | else 1276 | { 1277 | _rangeEncoder.encode(_isRep0Long, complexState, 1); 1278 | } 1279 | } 1280 | else 1281 | { 1282 | _rangeEncoder.encode(_isRepG0, _state, 1); 1283 | if (pos == 1) 1284 | { 1285 | _rangeEncoder.encode(_isRepG1, _state, 0); 1286 | } 1287 | else 1288 | { 1289 | _rangeEncoder.encode(_isRepG1, _state, 1); 1290 | _rangeEncoder.encode(_isRepG2, _state, pos - 2); 1291 | } 1292 | } 1293 | if (len == 1) 1294 | { 1295 | _state = Base.stateUpdateShortRep(_state); 1296 | } 1297 | else 1298 | { 1299 | _repMatchLenEncoder.encode(_rangeEncoder, len - Base.kMatchMinLen, posState); 1300 | _state = Base.stateUpdateRep(_state); 1301 | } 1302 | int distance = _repDistances[pos]; 1303 | if (pos != 0) 1304 | { 1305 | for (int i = pos; i >= 1; i--) 1306 | { 1307 | _repDistances[i] = _repDistances[i - 1]; 1308 | } 1309 | _repDistances[0] = distance; 1310 | } 1311 | } 1312 | else 1313 | { 1314 | _rangeEncoder.encode(_isRep, _state, 0); 1315 | _state = Base.stateUpdateMatch(_state); 1316 | _lenEncoder.encode(_rangeEncoder, len - Base.kMatchMinLen, posState); 1317 | pos -= Base.kNumRepDistances; 1318 | int posSlot = getPosSlot(pos); 1319 | int lenToPosState = Base.getLenToPosState(len); 1320 | _posSlotEncoder[lenToPosState].encode(_rangeEncoder, posSlot); 1321 | 1322 | if (posSlot >= Base.kStartPosModelIndex) 1323 | { 1324 | int footerBits = (posSlot >> 1) - 1; 1325 | int baseVal = ((2 | (posSlot & 1)) << footerBits); 1326 | int posReduced = pos - baseVal; 1327 | 1328 | if (posSlot < Base.kEndPosModelIndex) 1329 | { 1330 | BitTreeEncoder.reverseEncode(_posEncoders, 1331 | baseVal - posSlot - 1, _rangeEncoder, footerBits, posReduced); 1332 | } 1333 | else 1334 | { 1335 | _rangeEncoder.encodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits); 1336 | _posAlignEncoder.reverseEncode(_rangeEncoder, posReduced & Base.kAlignMask); 1337 | _alignPriceCount++; 1338 | } 1339 | } 1340 | int distance = pos; 1341 | for (int i = Base.kNumRepDistances - 1; i >= 1; i--) 1342 | { 1343 | _repDistances[i] = _repDistances[i - 1]; 1344 | } 1345 | _repDistances[0] = distance; 1346 | _matchPriceCount++; 1347 | } 1348 | _previousByte = _matchFinder.getIndexByte(len - 1 - _additionalOffset); 1349 | } 1350 | _additionalOffset -= len; 1351 | nowPos64 += len; 1352 | if (_additionalOffset == 0) 1353 | { 1354 | // if (!_fastMode) 1355 | if (_matchPriceCount >= (1 << 7)) 1356 | { 1357 | fillDistancesPrices(); 1358 | } 1359 | if (_alignPriceCount >= Base.kAlignTableSize) 1360 | { 1361 | fillAlignPrices(); 1362 | } 1363 | inSize[0] = nowPos64; 1364 | outSize[0] = _rangeEncoder.getProcessedSizeAdd(); 1365 | if (_matchFinder.getNumAvailableBytes() == 0) 1366 | { 1367 | flush((int) nowPos64); 1368 | return; 1369 | } 1370 | 1371 | if (nowPos64 - progressPosValuePrev >= (1 << 12)) 1372 | { 1373 | _finished = false; 1374 | finished[0] = false; 1375 | return; 1376 | } 1377 | } 1378 | } 1379 | } 1380 | 1381 | void releaseMFStream() 1382 | { 1383 | if (_matchFinder != null && _needReleaseMFStream) 1384 | { 1385 | _matchFinder.releaseStream(); 1386 | _needReleaseMFStream = false; 1387 | } 1388 | } 1389 | 1390 | void setOutStream(java.io.OutputStream outStream) 1391 | { 1392 | _rangeEncoder.setStream(outStream); 1393 | } 1394 | 1395 | void releaseOutStream() 1396 | { 1397 | _rangeEncoder.releaseStream(); 1398 | } 1399 | 1400 | void releaseStreams() 1401 | { 1402 | releaseMFStream(); 1403 | releaseOutStream(); 1404 | } 1405 | 1406 | void setStreams(java.io.InputStream inStream, java.io.OutputStream outStream 1407 | ) 1408 | { 1409 | _inStream = inStream; 1410 | _finished = false; 1411 | create(); 1412 | setOutStream(outStream); 1413 | init(); 1414 | 1415 | // if (!_fastMode) 1416 | { 1417 | fillDistancesPrices(); 1418 | fillAlignPrices(); 1419 | } 1420 | 1421 | _lenEncoder.setTableSize(_numFastBytes + 1 - Base.kMatchMinLen); 1422 | _lenEncoder.updateTables(1 << _posStateBits); 1423 | _repMatchLenEncoder.setTableSize(_numFastBytes + 1 - Base.kMatchMinLen); 1424 | _repMatchLenEncoder.updateTables(1 << _posStateBits); 1425 | 1426 | nowPos64 = 0; 1427 | } 1428 | 1429 | long[] processedInSize = new long[1]; 1430 | long[] processedOutSize = new long[1]; 1431 | boolean[] finished = new boolean[1]; 1432 | 1433 | public void code(java.io.InputStream inStream, java.io.OutputStream outStream, 1434 | long inSize, long outSize, ICodeProgress progress) throws IOException 1435 | { 1436 | _needReleaseMFStream = false; 1437 | try 1438 | { 1439 | setStreams(inStream, outStream); 1440 | while (true) 1441 | { 1442 | 1443 | 1444 | codeOneBlock(processedInSize, processedOutSize, finished); 1445 | if (finished[0]) 1446 | { 1447 | return; 1448 | } 1449 | if (progress != null) 1450 | { 1451 | progress.setProgress(processedInSize[0], processedOutSize[0]); 1452 | } 1453 | } 1454 | } 1455 | finally 1456 | { 1457 | releaseStreams(); 1458 | } 1459 | } 1460 | 1461 | public static final int kPropSize = 5; 1462 | byte[] properties = new byte[kPropSize]; 1463 | 1464 | public void writeCoderProperties(java.io.OutputStream outStream) throws IOException 1465 | { 1466 | properties[0] = (byte) ((_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits); 1467 | for (int i = 0; i < 4; i++) 1468 | { 1469 | properties[1 + i] = (byte) (_dictionarySize >> (8 * i)); 1470 | } 1471 | outStream.write(properties, 0, kPropSize); 1472 | } 1473 | 1474 | int[] tempPrices = new int[Base.kNumFullDistances]; 1475 | int _matchPriceCount; 1476 | 1477 | void fillDistancesPrices() 1478 | { 1479 | for (int i = Base.kStartPosModelIndex; i < Base.kNumFullDistances; i++) 1480 | { 1481 | int posSlot = getPosSlot(i); 1482 | int footerBits = (posSlot >> 1) - 1; 1483 | int baseVal = ((2 | (posSlot & 1)) << footerBits); 1484 | tempPrices[i] = BitTreeEncoder.reverseGetPrice(_posEncoders, 1485 | baseVal - posSlot - 1, footerBits, i - baseVal); 1486 | } 1487 | 1488 | for (int lenToPosState = 0; lenToPosState < Base.kNumLenToPosStates; lenToPosState++) 1489 | { 1490 | int posSlot; 1491 | BitTreeEncoder encoder = _posSlotEncoder[lenToPosState]; 1492 | 1493 | int st = (lenToPosState << Base.kNumPosSlotBits); 1494 | for (posSlot = 0; posSlot < _distTableSize; posSlot++) 1495 | { 1496 | _posSlotPrices[st + posSlot] = encoder.getPrice(posSlot); 1497 | } 1498 | for (posSlot = Base.kEndPosModelIndex; posSlot < _distTableSize; posSlot++) 1499 | { 1500 | _posSlotPrices[st + posSlot] += ((((posSlot >> 1) - 1) - Base.kNumAlignBits) << lzma.sdk.rangecoder.Encoder.kNumBitPriceShiftBits); 1501 | } 1502 | 1503 | int st2 = lenToPosState * Base.kNumFullDistances; 1504 | int i; 1505 | for (i = 0; i < Base.kStartPosModelIndex; i++) 1506 | { 1507 | _distancesPrices[st2 + i] = _posSlotPrices[st + i]; 1508 | } 1509 | for (; i < Base.kNumFullDistances; i++) 1510 | { 1511 | _distancesPrices[st2 + i] = _posSlotPrices[st + getPosSlot(i)] + tempPrices[i]; 1512 | } 1513 | } 1514 | _matchPriceCount = 0; 1515 | } 1516 | 1517 | void fillAlignPrices() 1518 | { 1519 | for (int i = 0; i < Base.kAlignTableSize; i++) 1520 | { 1521 | _alignPrices[i] = _posAlignEncoder.reverseGetPrice(i); 1522 | } 1523 | _alignPriceCount = 0; 1524 | } 1525 | 1526 | 1527 | public boolean setAlgorithm(int algorithm) 1528 | { 1529 | /* 1530 | _fastMode = (algorithm == 0); 1531 | _maxMode = (algorithm >= 2); 1532 | */ 1533 | return true; 1534 | } 1535 | 1536 | public boolean setDictionarySize(int dictionarySize) 1537 | { 1538 | int kDicLogSizeMaxCompress = 29; 1539 | if (dictionarySize < (1) || dictionarySize > (1 << kDicLogSizeMaxCompress)) 1540 | { 1541 | return false; 1542 | } 1543 | _dictionarySize = dictionarySize; 1544 | int dicLogSize; 1545 | for (dicLogSize = 0; dictionarySize > (1 << dicLogSize); dicLogSize++) 1546 | { 1547 | } 1548 | _distTableSize = dicLogSize * 2; 1549 | return true; 1550 | } 1551 | 1552 | public boolean setNumFastBytes(int numFastBytes) 1553 | { 1554 | if (numFastBytes < 5 || numFastBytes > Base.kMatchMaxLen) 1555 | { 1556 | return false; 1557 | } 1558 | _numFastBytes = numFastBytes; 1559 | return true; 1560 | } 1561 | 1562 | public boolean setMatchFinder(int matchFinderIndex) 1563 | { 1564 | if (matchFinderIndex < 0 || matchFinderIndex > 2) 1565 | { 1566 | return false; 1567 | } 1568 | int matchFinderIndexPrev = _matchFinderType; 1569 | _matchFinderType = matchFinderIndex; 1570 | if (_matchFinder != null && matchFinderIndexPrev != _matchFinderType) 1571 | { 1572 | _dictionarySizePrev = -1; 1573 | _matchFinder = null; 1574 | } 1575 | return true; 1576 | } 1577 | 1578 | public boolean setLcLpPb(int lc, int lp, int pb) 1579 | { 1580 | if ( 1581 | lp < 0 || lp > Base.kNumLitPosStatesBitsEncodingMax || 1582 | lc < 0 || lc > Base.kNumLitContextBitsMax || 1583 | pb < 0 || pb > Base.kNumPosStatesBitsEncodingMax) 1584 | { 1585 | return false; 1586 | } 1587 | _numLiteralPosStateBits = lp; 1588 | _numLiteralContextBits = lc; 1589 | _posStateBits = pb; 1590 | _posStateMask = ((1) << _posStateBits) - 1; 1591 | return true; 1592 | } 1593 | 1594 | public void setEndMarkerMode(boolean endMarkerMode) 1595 | { 1596 | _writeEndMark = endMarkerMode; 1597 | } 1598 | } 1599 | 1600 | --------------------------------------------------------------------------------