001: /*
002: * $RCSfile: BitOutputBuffer.java,v $
003: * $Revision: 1.1 $
004: * $Date: 2005/02/11 05:02:02 $
005: * $State: Exp $
006: *
007: * Class: BitOutputBuffer
008: *
009: * Description: <short description of class>
010: *
011: *
012: *
013: * COPYRIGHT:
014: *
015: * This software module was originally developed by Raphaël Grosbois and
016: * Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
017: * Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
018: * Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
019: * Centre France S.A) in the course of development of the JPEG2000
020: * standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
021: * software module is an implementation of a part of the JPEG 2000
022: * Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
023: * Systems AB and Canon Research Centre France S.A (collectively JJ2000
024: * Partners) agree not to assert against ISO/IEC and users of the JPEG
025: * 2000 Standard (Users) any of their rights under the copyright, not
026: * including other intellectual property rights, for this software module
027: * with respect to the usage by ISO/IEC and Users of this software module
028: * or modifications thereof for use in hardware or software products
029: * claiming conformance to the JPEG 2000 Standard. Those intending to use
030: * this software module in hardware or software products are advised that
031: * their use may infringe existing patents. The original developers of
032: * this software module, JJ2000 Partners and ISO/IEC assume no liability
033: * for use of this software module or modifications thereof. No license
034: * or right to this software module is granted for non JPEG 2000 Standard
035: * conforming products. JJ2000 Partners have full right to use this
036: * software module for his/her own purpose, assign or donate this
037: * software module to any third party and to inhibit third parties from
038: * using this software module for non JPEG 2000 Standard conforming
039: * products. This copyright notice must be included in all copies or
040: * derivative works of this software module.
041: *
042: * Copyright (c) 1999/2000 JJ2000 Partners.
043: * */
044: package jj2000.j2k.codestream.writer;
045:
046: import jj2000.j2k.util.*;
047:
048: /**
049: * This class implements a buffer for writing bits, with the required bit
050: * stuffing policy for the packet headers. The bits are stored in a byte array
051: * in the order in which they are written. The byte array is automatically
052: * reallocated and enlarged whenever necessary. A BitOutputBuffer object may
053: * be reused by calling its 'reset()' method.
054: *
055: * <P>NOTE: The methods implemented in this class are intended to be used only
056: * in writing packet heads, since a special bit stuffing procedure is used, as
057: * required for the packet heads.
058: * */
059: public class BitOutputBuffer {
060:
061: /** The buffer where we store the data */
062: byte buf[];
063:
064: /** The position of the current byte to write */
065: int curbyte;
066:
067: /** The number of available bits in the current byte */
068: int avbits = 8;
069:
070: /** The increment size for the buffer, 16 bytes. This is the
071: * number of bytes that are added to the buffer each time it is
072: * needed to enlarge it.*/
073: // This must be always 6 or larger.
074: public final static int SZ_INCR = 16;
075:
076: /** The initial size for the buffer, 32 bytes. */
077: public final static int SZ_INIT = 32;
078:
079: /**
080: * Creates a new BitOutputBuffer width a buffer of length
081: * 'SZ_INIT'.
082: * */
083: public BitOutputBuffer() {
084: buf = new byte[SZ_INIT];
085: }
086:
087: /**
088: * Resets the buffer. This rewinds the current position to the start of
089: * the buffer and sets all tha data to 0. Note that no new buffer is
090: * allocated, so this will affect any data that was returned by the
091: * 'getBuffer()' method.
092: * */
093: public void reset() {
094: int i;
095: // Reinit pointers
096: curbyte = 0;
097: avbits = 8;
098: ArrayUtil.byteArraySet(buf, (byte) 0);
099: }
100:
101: /**
102: * Writes a bit to the buffer at the current position. The value 'bit'
103: * must be either 0 or 1, otherwise it corrupts the bits that have been
104: * already written. The buffer is enlarged, by 'SZ_INCR' bytes, if
105: * necessary.
106: *
107: * <P>This method is declared final to increase performance.
108: *
109: * @param bit The bit to write, 0 or 1.
110: * */
111: public final void writeBit(int bit) {
112: buf[curbyte] |= bit << --avbits;
113: if (avbits > 0) {
114: // There is still place in current byte for next bit
115: return;
116: } else { // End of current byte => goto next
117: if (buf[curbyte] != (byte) 0xFF) { // We don't need bit stuffing
118: avbits = 8;
119: } else { // We need to stuff a bit (next MSBit is 0)
120: avbits = 7;
121: }
122: curbyte++;
123: if (curbyte == buf.length) {
124: // We are at end of 'buf' => extend it
125: byte oldbuf[] = buf;
126: buf = new byte[oldbuf.length + SZ_INCR];
127: System.arraycopy(oldbuf, 0, buf, 0, oldbuf.length);
128: }
129: }
130: }
131:
132: /**
133: * Writes the n least significant bits of 'bits' to the buffer at the
134: * current position. The least significant bit is written last. The 32-n
135: * most significant bits of 'bits' must be 0, otherwise corruption of the
136: * buffer will result. The buffer is enlarged, by 'SZ_INCR' bytes, if
137: * necessary.
138: *
139: * <P>This method is declared final to increase performance.
140: *
141: * @param bits The bits to write.
142: *
143: * @param n The number of LSBs in 'bits' to write.
144: * */
145: public final void writeBits(int bits, int n) {
146: // Check that we have enough place in 'buf' for n bits, and that we do
147: // not fill last byte, taking into account possibly stuffed bits (max
148: // 2)
149: if (((buf.length - curbyte) << 3) - 8 + avbits <= n + 2) {
150: // Not enough place, extend it
151: byte oldbuf[] = buf;
152: buf = new byte[oldbuf.length + SZ_INCR];
153: System.arraycopy(oldbuf, 0, buf, 0, oldbuf.length);
154: // SZ_INCR is always 6 or more, so it is enough to hold all the
155: // new bits plus the ones to come after
156: }
157: // Now write the bits
158: if (n >= avbits) {
159: // Complete the current byte
160: n -= avbits;
161: buf[curbyte] |= bits >> n;
162: if (buf[curbyte] != (byte) 0xFF) { // We don't need bit stuffing
163: avbits = 8;
164: } else { // We need to stuff a bit (next MSBit is 0)
165: avbits = 7;
166: }
167: curbyte++;
168: // Write whole bytes
169: while (n >= avbits) {
170: n -= avbits;
171: buf[curbyte] |= (bits >> n) & (~(1 << avbits));
172: if (buf[curbyte] != (byte) 0xFF) { // We don't need bit
173: // stuffing
174: avbits = 8;
175: } else { // We need to stuff a bit (next MSBit is 0)
176: avbits = 7;
177: }
178: curbyte++;
179: }
180: }
181: // Finish last byte (we know that now n < avbits)
182: if (n > 0) {
183: avbits -= n;
184: buf[curbyte] |= (bits & ((1 << n) - 1)) << avbits;
185: }
186: if (avbits == 0) { // Last byte is full
187: if (buf[curbyte] != (byte) 0xFF) { // We don't need bit stuffing
188: avbits = 8;
189: } else { // We need to stuff a bit (next MSBit is 0)
190: avbits = 7;
191: }
192: curbyte++; // We already ensured that we have enough place
193: }
194: }
195:
196: /**
197: * Returns the current length of the buffer, in bytes.
198: *
199: * <P>This method is declared final to increase performance.
200: *
201: * @return The currebt length of the buffer in bytes.
202: * */
203: public final int getLength() {
204: if (avbits == 8) { // A integral number of bytes
205: return curbyte;
206: } else { // Some bits in last byte
207: return curbyte + 1;
208: }
209: }
210:
211: /**
212: * Returns the byte buffer. This is the internal byte buffer so it should
213: * not be modified. Only the first N elements have valid data, where N is
214: * the value returned by 'getLength()'
215: *
216: * <P>This method is declared final to increase performance.
217: *
218: * @return The internal byte buffer.
219: * */
220: public final byte[] getBuffer() {
221: return buf;
222: }
223:
224: /**
225: * Returns the byte buffer data in a new array. This is a copy of the
226: * internal byte buffer. If 'data' is non-null it is used to return the
227: * data. This array should be large enough to contain all the data,
228: * otherwise a IndexOutOfBoundsException is thrown by the Java system. The
229: * number of elements returned is what 'getLength()' returns.
230: *
231: * @param data If non-null this array is used to return the data, which
232: * mus be large enough. Otherwise a new one is created and returned.
233: *
234: * @return The byte buffer data.
235: * */
236: public byte[] toByteArray(byte data[]) {
237: if (data == null) {
238: data = new byte[(avbits == 8) ? curbyte : curbyte + 1];
239: }
240: System.arraycopy(buf, 0, data, 0, (avbits == 8) ? curbyte
241: : curbyte + 1);
242: return data;
243: }
244:
245: /**
246: * Prints information about this object for debugging purposes
247: *
248: * @return Information about the object.
249: * */
250: public String toString() {
251: return "bits written = " + (curbyte * 8 + (8 - avbits))
252: + ", curbyte = " + curbyte + ", avbits = " + avbits;
253: }
254: }
|