    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.mylzw;
    018
    019import java.io.FilterInputStream;
    020import java.io.IOException;
    021import java.io.InputStream;
    022import java.nio.ByteOrder;
    023
    024public class MyBitInputStream extends FilterInputStream {
    025    private final ByteOrder byteOrder;
    026    private final boolean tiffLZWMode;
    027    private long bytesRead;
    028    private int bitsInCache;
    029    private int bitCache;
    030
    031    public MyBitInputStream(final InputStream is, final ByteOrder byteOrder, final boolean tiffLZWMode) {
    032        super(is);
    033        this.byteOrder = byteOrder;
    034        this.tiffLZWMode = tiffLZWMode;
    035    }
    036
    037    public void flushCache() {
    038        bitsInCache = 0;
    039        bitCache = 0;
    040    }
    041
    042    public long getBytesRead() {
    043        return bytesRead;
    044    }
    045
    046    @Override
    047    public int read() throws IOException {
    048        return readBits(8);
    049    }
    050
    051    public int readBits(final int sampleBits) throws IOException {
    052        while (bitsInCache < sampleBits) {
    053            final int next = in.read();
    054
    055            if (next < 0) {
    056                if (tiffLZWMode) {
    057                    // pernicious special case!
    058                    return 257;
    059                }
    060                return -1;
    061            }
    062
    063            final int newByte = 0xff & next;
    064
    065            if (byteOrder == ByteOrder.BIG_ENDIAN) {
    066                bitCache = bitCache << 8 | newByte;
    067            } else {
    068                bitCache = newByte << bitsInCache | bitCache;
    069            }
    070
    071            bytesRead++;
    072            bitsInCache += 8;
    073        }
    074        final int sampleMask = (1 << sampleBits) - 1;
    075
    076        final int sample;
    077
    078        if (byteOrder == ByteOrder.BIG_ENDIAN) {
    079            sample = sampleMask & bitCache >> bitsInCache - sampleBits;
    080        } else {
    081            sample = sampleMask & bitCache;
    082            bitCache >>= sampleBits;
    083        }
    084
    085        final int result = sample;
    086
    087        bitsInCache -= sampleBits;
    088        final int remainderMask = (1 << bitsInCache) - 1;
    089        bitCache &= remainderMask;
    090
    091        return result;
    092    }
    093
    094}