    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.imaging.common.mylzw;
    018
    019import java.io.IOException;
    020import java.io.InputStream;
    021import java.nio.ByteOrder;
    022
    023public class MyBitInputStream extends InputStream {
    024    private final InputStream is;
    025    private final ByteOrder byteOrder;
    026    private boolean tiffLZWMode;
    027    private long bytesRead;
    028    private int bitsInCache;
    029    private int bitCache;
    030
    031    public MyBitInputStream(final InputStream is, final ByteOrder byteOrder) {
    032        this.byteOrder = byteOrder;
    033        this.is = is;
    034    }
    035
    036    @Override
    037    public int read() throws IOException {
    038        return readBits(8);
    039    }
    040
    041    public void setTiffLZWMode() {
    042        tiffLZWMode = true;
    043    }
    044
    045    public int readBits(final int sampleBits) throws IOException {
    046        while (bitsInCache < sampleBits) {
    047            final int next = is.read();
    048
    049            if (next < 0) {
    050                if (tiffLZWMode) {
    051                    // pernicious special case!
    052                    return 257;
    053                }
    054                return -1;
    055            }
    056
    057            final int newByte = (0xff & next);
    058
    059            if (byteOrder == ByteOrder.BIG_ENDIAN) {
    060                bitCache = (bitCache << 8) | newByte;
    061            } else {
    062                bitCache = (newByte << bitsInCache) | bitCache;
    063            }
    064
    065            bytesRead++;
    066            bitsInCache += 8;
    067        }
    068        final int sampleMask = (1 << sampleBits) - 1;
    069
    070        int sample;
    071
    072        if (byteOrder == ByteOrder.BIG_ENDIAN) {
    073            sample = sampleMask & (bitCache >> (bitsInCache - sampleBits));
    074        } else {
    075            sample = sampleMask & bitCache;
    076            bitCache >>= sampleBits;
    077        }
    078
    079        final int result = sample;
    080
    081        bitsInCache -= sampleBits;
    082        final int remainderMask = (1 << bitsInCache) - 1;
    083        bitCache &= remainderMask;
    084
    085        return result;
    086    }
    087
    088    public void flushCache() {
    089        bitsInCache = 0;
    090        bitCache = 0;
    091    }
    092
    093    public long getBytesRead() {
    094        return bytesRead;
    095    }
    096
    097}