org.apache.pdfbox.io.ccitt.PackedBitArray Maven / Gradle / Ivy
Show all versions of pdfbox Show documentation
/*
* 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.
*/
/* $Id: PackedBitArray.java 1156213 2011-08-10 15:06:20Z jeremias $ */
package org.apache.pdfbox.io.ccitt;
/**
* Represents an array of bits packed in a byte array of fixed size.
* @version $Revision$
*/
public class PackedBitArray
{
private int bitCount;
private byte[] data;
/**
* Constructs a new bit array.
* @param bitCount the number of bits to maintain
*/
public PackedBitArray(int bitCount)
{
this.bitCount = bitCount;
int byteCount = (bitCount + 7) / 8;
this.data = new byte[byteCount];
}
private int byteOffset(int offset)
{
return offset / 8;
}
private int bitOffset(int offset)
{
return offset % 8;
}
/**
* Sets a bit at the given offset.
* @param offset the offset
*/
public void set(int offset)
{
int byteOffset = byteOffset(offset);
this.data[byteOffset] |= 1 << bitOffset(offset);
}
/**
* Clears a bit at the given offset.
* @param offset the offset
*/
public void clear(int offset)
{
int byteOffset = byteOffset(offset);
int bitOffset = bitOffset(offset);
this.data[byteOffset] &= ~(1 << bitOffset);
}
/**
* Sets a run of bits at the given offset to either 1 or 0.
* @param offset the offset
* @param length the number of bits to set
* @param bit 1 to set the bit, 0 to clear it
*/
public void setBits(int offset, int length, int bit)
{
if (bit == 0)
{
clearBits(offset, length);
}
else
{
setBits(offset, length);
}
}
/**
* Sets a run of bits at the given offset to either 1.
* @param offset the offset
* @param length the number of bits to set
*/
public void setBits(int offset, int length)
{
if (length == 0)
{
return;
}
int startBitOffset = bitOffset(offset);
int firstByte = byteOffset(offset);
int lastBitOffset = offset + length;
if (lastBitOffset > getBitCount())
{
throw new IndexOutOfBoundsException("offset + length > bit count");
}
int lastByte = byteOffset(lastBitOffset);
int endBitOffset = bitOffset(lastBitOffset);
if (firstByte == lastByte)
{
//Only one byte affected
int mask = (1 << endBitOffset) - (1 << startBitOffset);
this.data[firstByte] |= mask;
}
else
{
//Bits spanning multiple bytes
this.data[firstByte] |= 0xFF << startBitOffset;
for (int i = firstByte + 1; i < lastByte; i++)
{
this.data[i] = (byte)0xFF;
}
if (endBitOffset > 0)
{
this.data[lastByte] |= 0xFF >> (8 - endBitOffset);
}
}
}
/**
* Clears a run of bits at the given offset.
* @param offset the offset
* @param length the number of bits to clear
*/
public void clearBits(int offset, int length)
{
if (length == 0)
{
return;
}
int startBitOffset = offset % 8;
int firstByte = byteOffset(offset);
int lastBitOffset = offset + length;
int lastByte = byteOffset(lastBitOffset);
int endBitOffset = lastBitOffset % 8;
if (firstByte == lastByte)
{
//Only one byte affected
int mask = (1 << endBitOffset) - (1 << startBitOffset);
this.data[firstByte] &= ~mask;
}
else
{
//Bits spanning multiple bytes
this.data[firstByte] &= ~(0xFF << startBitOffset);
for (int i = firstByte + 1; i < lastByte; i++)
{
this.data[i] = (byte)0x00;
}
if (endBitOffset > 0)
{
this.data[lastByte] &= ~(0xFF >> (8 - endBitOffset));
}
}
}
/**
* Clear all bits in the array.
*/
public void clear()
{
clearBits(0, getBitCount());
}
/**
* Returns the number of bits maintained by this array.
* @return the number of bits
*/
public int getBitCount()
{
return this.bitCount;
}
/**
* Returns the size of the byte buffer for this array.
* @return the size of the byte buffer
*/
public int getByteCount()
{
return this.data.length;
}
/**
* Returns the underlying byte buffer.
*
* Note: the actual buffer is returned. If it's manipulated
* the content of the bit array changes.
* @return the underlying data buffer
*/
public byte[] getData()
{
return this.data;
}
/** {@inheritDoc} */
public String toString()
{
return toBitString(this.data).substring(0, this.bitCount);
}
/**
* Converts a byte to a "binary" String of 0s and 1s.
* @param data the value to convert
* @return the binary string
*/
public static String toBitString(byte data)
{
byte[] buf = new byte[] {data};
return toBitString(buf);
}
/**
* Converts a series of bytes to a "binary" String of 0s and 1s.
* @param data the data
* @return the binary string
*/
public static String toBitString(byte[] data)
{
return toBitString(data, 0, data.length);
}
/**
* Converts a series of bytes to a "binary" String of 0s and 1s.
* @param data the data
* @param start the start offset
* @param len the number of bytes to convert
* @return the binary string
*/
public static String toBitString(byte[] data, int start, int len)
{
StringBuffer sb = new StringBuffer();
for (int x = start, end = start + len; x < end; x++)
{
for (int i = 0; i < 8; i++)
{
int mask = 1 << i;
int value = data[x] & mask;
sb.append(value != 0 ? '1' : '0');
}
}
return sb.toString();
}
}