| /* Copyright 2015 Google Inc. All Rights Reserved. |
| |
| Distributed under MIT license. |
| See file LICENSE for detail or copy at https://opensource.org/licenses/MIT |
| */ |
| |
| package org.brotli.dec; |
| |
| import static org.brotli.dec.RunningState.BLOCK_START; |
| import static org.brotli.dec.RunningState.CLOSED; |
| import static org.brotli.dec.RunningState.UNINITIALIZED; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| |
| final class State { |
| int runningState = UNINITIALIZED; |
| int nextRunningState; |
| final BitReader br = new BitReader(); |
| byte[] ringBuffer; |
| final int[] blockTypeTrees = new int[3 * Huffman.HUFFMAN_MAX_TABLE_SIZE]; |
| final int[] blockLenTrees = new int[3 * Huffman.HUFFMAN_MAX_TABLE_SIZE]; |
| |
| // Current meta-block header information. |
| int metaBlockLength; |
| boolean inputEnd; |
| boolean isUncompressed; |
| boolean isMetadata; |
| |
| final HuffmanTreeGroup hGroup0 = new HuffmanTreeGroup(); |
| final HuffmanTreeGroup hGroup1 = new HuffmanTreeGroup(); |
| final HuffmanTreeGroup hGroup2 = new HuffmanTreeGroup(); |
| final int[] blockLength = new int[3]; |
| final int[] numBlockTypes = new int[3]; |
| final int[] blockTypeRb = new int[6]; |
| final int[] distRb = {16, 15, 11, 4}; |
| int pos = 0; |
| int maxDistance = 0; |
| int distRbIdx = 0; |
| boolean trivialLiteralContext = false; |
| int literalTreeIndex = 0; |
| int literalTree; |
| int j; |
| int insertLength; |
| byte[] contextModes; |
| byte[] contextMap; |
| int contextMapSlice; |
| int distContextMapSlice; |
| int contextLookupOffset1; |
| int contextLookupOffset2; |
| int treeCommandOffset; |
| int distanceCode; |
| byte[] distContextMap; |
| int numDirectDistanceCodes; |
| int distancePostfixMask; |
| int distancePostfixBits; |
| int distance; |
| int copyLength; |
| int copyDst; |
| int maxBackwardDistance; |
| int maxRingBufferSize; |
| int ringBufferSize = 0; |
| long expectedTotalSize = 0; |
| byte[] customDictionary = new byte[0]; |
| int bytesToIgnore = 0; |
| |
| int outputOffset; |
| int outputLength; |
| int outputUsed; |
| int bytesWritten; |
| int bytesToWrite; |
| byte[] output; |
| |
| // TODO: Update to current spec. |
| private static int decodeWindowBits(BitReader br) { |
| if (BitReader.readBits(br, 1) == 0) { |
| return 16; |
| } |
| int n = BitReader.readBits(br, 3); |
| if (n != 0) { |
| return 17 + n; |
| } |
| n = BitReader.readBits(br, 3); |
| if (n != 0) { |
| return 8 + n; |
| } |
| return 17; |
| } |
| |
| /** |
| * Associate input with decoder state. |
| * |
| * @param state uninitialized state without associated input |
| * @param input compressed data source |
| */ |
| static void setInput(State state, InputStream input) { |
| if (state.runningState != UNINITIALIZED) { |
| throw new IllegalStateException("State MUST be uninitialized"); |
| } |
| BitReader.init(state.br, input); |
| int windowBits = decodeWindowBits(state.br); |
| if (windowBits == 9) { /* Reserved case for future expansion. */ |
| throw new BrotliRuntimeException("Invalid 'windowBits' code"); |
| } |
| state.maxRingBufferSize = 1 << windowBits; |
| state.maxBackwardDistance = state.maxRingBufferSize - 16; |
| state.runningState = BLOCK_START; |
| } |
| |
| static void close(State state) throws IOException { |
| if (state.runningState == UNINITIALIZED) { |
| throw new IllegalStateException("State MUST be initialized"); |
| } |
| if (state.runningState == CLOSED) { |
| return; |
| } |
| state.runningState = CLOSED; |
| BitReader.close(state.br); |
| } |
| } |