/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.commons.compress.archivers.zip;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteOrder;

import org.apache.commons.compress.compressors.lzw.LZWInputStream;

Input stream that decompresses ZIP method 1 (unshrinking). A variation of the LZW algorithm, with some twists.
@NotThreadSafe
Since:1.7
/** * Input stream that decompresses ZIP method 1 (unshrinking). A variation of the LZW algorithm, with some twists. * @NotThreadSafe * @since 1.7 */
class UnshrinkingInputStream extends LZWInputStream { private static final int MAX_CODE_SIZE = 13; private static final int MAX_TABLE_SIZE = 1 << MAX_CODE_SIZE; private final boolean[] isUsed;
IOException is not actually thrown!
Params:
  • inputStream –
Throws:
/** * IOException is not actually thrown! * * @param inputStream * @throws IOException IOException is not actually thrown! */
public UnshrinkingInputStream(final InputStream inputStream) throws IOException { super(inputStream, ByteOrder.LITTLE_ENDIAN); setClearCode(DEFAULT_CODE_SIZE); initializeTables(MAX_CODE_SIZE); isUsed = new boolean[getPrefixesLength()]; for (int i = 0; i < (1 << 8); i++) { isUsed[i] = true; } setTableSize(getClearCode() + 1); } @Override protected int addEntry(final int previousCode, final byte character) throws IOException { int tableSize = getTableSize(); while ((tableSize < MAX_TABLE_SIZE) && isUsed[tableSize]) { tableSize++; } setTableSize(tableSize); final int idx = addEntry(previousCode, character, MAX_TABLE_SIZE); if (idx >= 0) { isUsed[idx] = true; } return idx; } private void partialClear() { final boolean[] isParent = new boolean[MAX_TABLE_SIZE]; for (int i = 0; i < isUsed.length; i++) { if (isUsed[i] && getPrefix(i) != UNUSED_PREFIX) { isParent[getPrefix(i)] = true; } } for (int i = getClearCode() + 1; i < isParent.length; i++) { if (!isParent[i]) { isUsed[i] = false; setPrefix(i, UNUSED_PREFIX); } } } @Override protected int decompressNextSymbol() throws IOException { // // table entry table entry // _____________ _____ // table entry / \ / \ // ____________/ \ \ // / / \ / \ \ // +---+---+---+---+---+---+---+---+---+---+ // | . | . | . | . | . | . | . | . | . | . | // +---+---+---+---+---+---+---+---+---+---+ // |<--------->|<------------->|<----->|<->| // symbol symbol symbol symbol // final int code = readNextCode(); if (code < 0) { return -1; } else if (code == getClearCode()) { final int subCode = readNextCode(); if (subCode < 0) { throw new IOException("Unexpected EOF;"); } else if (subCode == 1) { if (getCodeSize() < MAX_CODE_SIZE) { incrementCodeSize(); } else { throw new IOException("Attempt to increase code size beyond maximum"); } } else if (subCode == 2) { partialClear(); setTableSize(getClearCode() + 1); } else { throw new IOException("Invalid clear code subcode " + subCode); } return 0; } else { boolean addedUnfinishedEntry = false; int effectiveCode = code; if (!isUsed[code]) { effectiveCode = addRepeatOfPreviousCode(); addedUnfinishedEntry = true; } return expandCodeToOutputStack(effectiveCode, addedUnfinishedEntry); } } }