summaryrefslogtreecommitdiff
path: root/songdbj/de/jarnbjo/util/io
diff options
context:
space:
mode:
Diffstat (limited to 'songdbj/de/jarnbjo/util/io')
-rw-r--r--songdbj/de/jarnbjo/util/io/BitInputStream.java185
-rw-r--r--songdbj/de/jarnbjo/util/io/ByteArrayBitInputStream.java352
-rw-r--r--songdbj/de/jarnbjo/util/io/HuffmanNode.java144
3 files changed, 681 insertions, 0 deletions
diff --git a/songdbj/de/jarnbjo/util/io/BitInputStream.java b/songdbj/de/jarnbjo/util/io/BitInputStream.java
new file mode 100644
index 0000000000..89cadb8380
--- /dev/null
+++ b/songdbj/de/jarnbjo/util/io/BitInputStream.java
@@ -0,0 +1,185 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.5 2003/04/10 19:48:31 jarnbjo
25 * no message
26 *
27 * Revision 1.4 2003/03/16 20:57:06 jarnbjo
28 * no message
29 *
30 * Revision 1.3 2003/03/16 20:56:56 jarnbjo
31 * no message
32 *
33 * Revision 1.2 2003/03/16 01:11:39 jarnbjo
34 * no message
35 *
36 * Revision 1.1 2003/03/03 21:02:20 jarnbjo
37 * no message
38 *
39 */
40
41package de.jarnbjo.util.io;
42
43import java.io.IOException;
44
45/**
46 * An interface with methods allowing bit-wise reading from
47 * an input stream. All methods in this interface are optional
48 * and an implementation not support a method or a specific state
49 * (e.g. endian) will throw an UnspportedOperationException if
50 * such a method is being called. This should be speicified in
51 * the implementation documentation.
52 */
53
54public interface BitInputStream {
55
56 /**
57 * constant for setting this stream's mode to little endian
58 *
59 * @see #setEndian(int)
60 */
61
62 public static final int LITTLE_ENDIAN = 0;
63
64 /**
65 * constant for setting this stream's mode to big endian
66 *
67 * @see #setEndian(int)
68 */
69
70 public static final int BIG_ENDIAN = 1;
71
72 /**
73 * reads one bit (as a boolean) from the input stream
74 *
75 * @return <code>true</code> if the next bit is 1,
76 * <code>false</code> otherwise
77 *
78 * @throws IOException if an I/O error occurs
79 * @throws UnsupportedOperationException if the method is not supported by the implementation
80 */
81
82 public boolean getBit() throws IOException;
83
84 /**
85 * reads <code>bits</code> number of bits from the input
86 * stream
87 *
88 * @return the unsigned integer value read from the stream
89 *
90 * @throws IOException if an I/O error occurs
91 * @throws UnsupportedOperationException if the method is not supported by the implementation
92 */
93
94 public int getInt(int bits) throws IOException;
95
96 /**
97 * reads <code>bits</code> number of bits from the input
98 * stream
99 *
100 * @return the signed integer value read from the stream
101 *
102 * @throws IOException if an I/O error occurs
103 * @throws UnsupportedOperationException if the method is not supported by the implementation
104 */
105
106 public int getSignedInt(int bits) throws IOException;
107
108 /**
109 * reads a huffman codeword based on the <code>root</code>
110 * parameter and returns the decoded value
111 *
112 * @param root the root of the Huffman tree used to decode the codeword
113 * @return the decoded unsigned integer value read from the stream
114 *
115 * @throws IOException if an I/O error occurs
116 * @throws UnsupportedOperationException if the method is not supported by the implementation
117 */
118
119 public int getInt(HuffmanNode root) throws IOException;
120
121 /**
122 * reads an integer encoded as "signed rice" as described in
123 * the FLAC audio format specification
124 *
125 * @param order
126 * @return the decoded integer value read from the stream
127 *
128 * @throws IOException if an I/O error occurs
129 * @throws UnsupportedOperationException if the method is not supported by the implementation
130 */
131
132 public int readSignedRice(int order) throws IOException;
133
134 /**
135 * fills the array from <code>offset</code> with <code>len</code>
136 * integers encoded as "signed rice" as described in
137 * the FLAC audio format specification
138 *
139 * @param order
140 * @param buffer
141 * @param offset
142 * @param len
143 * @return the decoded integer value read from the stream
144 *
145 * @throws IOException if an I/O error occurs
146 * @throws UnsupportedOperationException if the method is not supported by the implementation
147 */
148
149 public void readSignedRice(int order, int[] buffer, int offset, int len) throws IOException;
150
151 /**
152 * reads <code>bits</code> number of bits from the input
153 * stream
154 *
155 * @return the unsigned long value read from the stream
156 *
157 * @throws IOException if an I/O error occurs
158 * @throws UnsupportedOperationException if the method is not supported by the implementation
159 */
160
161 public long getLong(int bits) throws IOException;
162
163 /**
164 * causes the read pointer to be moved to the beginning
165 * of the next byte, remaining bits in the current byte
166 * are discarded
167 *
168 * @throws UnsupportedOperationException if the method is not supported by the implementation
169 */
170
171 public void align();
172
173 /**
174 * changes the endian mode used when reading bit-wise from
175 * the stream, changing the mode mid-stream will cause the
176 * read cursor to move to the beginning of the next byte
177 * (as if calling the <code>allign</code> method
178 *
179 * @see #align()
180 *
181 * @throws UnsupportedOperationException if the method is not supported by the implementation
182 */
183
184 public void setEndian(int endian);
185} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/util/io/ByteArrayBitInputStream.java b/songdbj/de/jarnbjo/util/io/ByteArrayBitInputStream.java
new file mode 100644
index 0000000000..9c84c7daca
--- /dev/null
+++ b/songdbj/de/jarnbjo/util/io/ByteArrayBitInputStream.java
@@ -0,0 +1,352 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.3 2003/04/10 19:48:31 jarnbjo
25 * no message
26 *
27 * Revision 1.2 2003/03/16 01:11:39 jarnbjo
28 * no message
29 *
30 * Revision 1.1 2003/03/03 21:02:20 jarnbjo
31 * no message
32 *
33 */
34
35package de.jarnbjo.util.io;
36
37import java.io.IOException;
38
39/**
40 * Implementation of the <code>BitInputStream</code> interface,
41 * using a byte array as data source.
42*/
43
44public class ByteArrayBitInputStream implements BitInputStream {
45
46 private byte[] source;
47 private byte currentByte;
48
49 private int endian;
50
51 private int byteIndex=0;
52 private int bitIndex=0;
53
54 public ByteArrayBitInputStream(byte[] source) {
55 this(source, LITTLE_ENDIAN);
56 }
57
58 public ByteArrayBitInputStream(byte[] source, int endian) {
59 this.endian=endian;
60 this.source=source;
61 currentByte=source[0];
62 bitIndex=(endian==LITTLE_ENDIAN)?0:7;
63 }
64
65 public boolean getBit() throws IOException {
66 if(endian==LITTLE_ENDIAN) {
67 if(bitIndex>7) {
68 bitIndex=0;
69 currentByte=source[++byteIndex];
70 }
71 return (currentByte&(1<<(bitIndex++)))!=0;
72 }
73 else {
74 if(bitIndex<0) {
75 bitIndex=7;
76 currentByte=source[++byteIndex];
77 }
78 return (currentByte&(1<<(bitIndex--)))!=0;
79 }
80 }
81
82 public int getInt(int bits) throws IOException {
83 if(bits>32) {
84 throw new IllegalArgumentException("Argument \"bits\" must be <= 32");
85 }
86 int res=0;
87 if(endian==LITTLE_ENDIAN) {
88 for(int i=0; i<bits; i++) {
89 if(getBit()) {
90 res|=(1<<i);
91 }
92 }
93 }
94 else {
95 if(bitIndex<0) {
96 bitIndex=7;
97 currentByte=source[++byteIndex];
98 }
99 if(bits<=bitIndex+1) {
100 int ci=((int)currentByte)&0xff;
101 int offset=1+bitIndex-bits;
102 int mask=((1<<bits)-1)<<offset;
103 res=(ci&mask)>>offset;
104 bitIndex-=bits;
105 }
106 else {
107 res=(((int)currentByte)&0xff&((1<<(bitIndex+1))-1))<<(bits-bitIndex-1);
108 bits-=bitIndex+1;
109 currentByte=source[++byteIndex];
110 while(bits>=8) {
111 bits-=8;
112 res|=(((int)source[byteIndex])&0xff)<<bits;
113 currentByte=source[++byteIndex];
114 }
115 if(bits>0) {
116 int ci=((int)source[byteIndex])&0xff;
117 res|=(ci>>(8-bits))&((1<<bits)-1);
118 bitIndex=7-bits;
119 }
120 else {
121 currentByte=source[--byteIndex];
122 bitIndex=-1;
123 }
124 }
125 }
126
127 return res;
128 }
129
130 public int getSignedInt(int bits) throws IOException {
131 int raw=getInt(bits);
132 if(raw>=1<<(bits-1)) {
133 raw-=1<<bits;
134 }
135 return raw;
136 }
137
138 public int getInt(HuffmanNode root) throws IOException {
139 while(root.value==null) {
140 if(bitIndex>7) {
141 bitIndex=0;
142 currentByte=source[++byteIndex];
143 }
144 root=(currentByte&(1<<(bitIndex++)))!=0?root.o1:root.o0;
145 }
146 return root.value.intValue();
147 }
148
149 public long getLong(int bits) throws IOException {
150 if(bits>64) {
151 throw new IllegalArgumentException("Argument \"bits\" must be <= 64");
152 }
153 long res=0;
154 if(endian==LITTLE_ENDIAN) {
155 for(int i=0; i<bits; i++) {
156 if(getBit()) {
157 res|=(1L<<i);
158 }
159 }
160 }
161 else {
162 for(int i=bits-1; i>=0; i--) {
163 if(getBit()) {
164 res|=(1L<<i);
165 }
166 }
167 }
168 return res;
169 }
170
171 /**
172 * <p>reads an integer encoded as "signed rice" as described in
173 * the FLAC audio format specification</p>
174 *
175 * <p><b>not supported for little endian</b></p>
176 *
177 * @param order
178 * @return the decoded integer value read from the stream
179 *
180 * @throws IOException if an I/O error occurs
181 * @throws UnsupportedOperationException if the method is not supported by the implementation
182 */
183
184 public int readSignedRice(int order) throws IOException {
185
186 int msbs=-1, lsbs=0, res=0;
187
188 if(endian==LITTLE_ENDIAN) {
189 // little endian
190 throw new UnsupportedOperationException("ByteArrayBitInputStream.readSignedRice() is only supported in big endian mode");
191 }
192 else {
193 // big endian
194
195 byte cb=source[byteIndex];
196 do {
197 msbs++;
198 if(bitIndex<0) {
199 bitIndex=7;
200 byteIndex++;
201 cb=source[byteIndex];
202 }
203 } while((cb&(1<<bitIndex--))==0);
204
205 int bits=order;
206
207 if(bitIndex<0) {
208 bitIndex=7;
209 byteIndex++;
210 }
211 if(bits<=bitIndex+1) {
212 int ci=((int)source[byteIndex])&0xff;
213 int offset=1+bitIndex-bits;
214 int mask=((1<<bits)-1)<<offset;
215 lsbs=(ci&mask)>>offset;
216 bitIndex-=bits;
217 }
218 else {
219 lsbs=(((int)source[byteIndex])&0xff&((1<<(bitIndex+1))-1))<<(bits-bitIndex-1);
220 bits-=bitIndex+1;
221 byteIndex++;
222 while(bits>=8) {
223 bits-=8;
224 lsbs|=(((int)source[byteIndex])&0xff)<<bits;
225 byteIndex++;
226 }
227 if(bits>0) {
228 int ci=((int)source[byteIndex])&0xff;
229 lsbs|=(ci>>(8-bits))&((1<<bits)-1);
230 bitIndex=7-bits;
231 }
232 else {
233 byteIndex--;
234 bitIndex=-1;
235 }
236 }
237
238 res=(msbs<<order)|lsbs;
239 }
240
241 return (res&1)==1?-(res>>1)-1:(res>>1);
242 }
243
244 /**
245 * <p>fills the array from <code>offset</code> with <code>len</code>
246 * integers encoded as "signed rice" as described in
247 * the FLAC audio format specification</p>
248 *
249 * <p><b>not supported for little endian</b></p>
250 *
251 * @param order
252 * @param buffer
253 * @param offset
254 * @param len
255 * @return the decoded integer value read from the stream
256 *
257 * @throws IOException if an I/O error occurs
258 * @throws UnsupportedOperationException if the method is not supported by the implementation
259 */
260
261 public void readSignedRice(int order, int[] buffer, int off, int len) throws IOException {
262
263 if(endian==LITTLE_ENDIAN) {
264 // little endian
265 throw new UnsupportedOperationException("ByteArrayBitInputStream.readSignedRice() is only supported in big endian mode");
266 }
267 else {
268 // big endian
269 for(int i=off; i<off+len; i++) {
270
271 int msbs=-1, lsbs=0;
272
273 byte cb=source[byteIndex];
274 do {
275 msbs++;
276 if(bitIndex<0) {
277 bitIndex=7;
278 byteIndex++;
279 cb=source[byteIndex];
280 }
281 } while((cb&(1<<bitIndex--))==0);
282
283 int bits=order;
284
285 if(bitIndex<0) {
286 bitIndex=7;
287 byteIndex++;
288 }
289 if(bits<=bitIndex+1) {
290 int ci=((int)source[byteIndex])&0xff;
291 int offset=1+bitIndex-bits;
292 int mask=((1<<bits)-1)<<offset;
293 lsbs=(ci&mask)>>offset;
294 bitIndex-=bits;
295 }
296 else {
297 lsbs=(((int)source[byteIndex])&0xff&((1<<(bitIndex+1))-1))<<(bits-bitIndex-1);
298 bits-=bitIndex+1;
299 byteIndex++;
300 while(bits>=8) {
301 bits-=8;
302 lsbs|=(((int)source[byteIndex])&0xff)<<bits;
303 byteIndex++;
304 }
305 if(bits>0) {
306 int ci=((int)source[byteIndex])&0xff;
307 lsbs|=(ci>>(8-bits))&((1<<bits)-1);
308 bitIndex=7-bits;
309 }
310 else {
311 byteIndex--;
312 bitIndex=-1;
313 }
314 }
315
316 int res=(msbs<<order)|lsbs;
317 buffer[i]=(res&1)==1?-(res>>1)-1:(res>>1);
318 }
319 }
320 }
321
322 public void align() {
323 if(endian==BIG_ENDIAN && bitIndex>=0) {
324 bitIndex=7;
325 byteIndex++;
326 }
327 else if(endian==LITTLE_ENDIAN && bitIndex<=7) {
328 bitIndex=0;
329 byteIndex++;
330 }
331 }
332
333 public void setEndian(int endian) {
334 if(this.endian==BIG_ENDIAN && endian==LITTLE_ENDIAN) {
335 bitIndex=0;
336 byteIndex++;
337 }
338 else if(this.endian==LITTLE_ENDIAN && endian==BIG_ENDIAN) {
339 bitIndex=7;
340 byteIndex++;
341 }
342 this.endian=endian;
343 }
344
345 /**
346 * @return the byte array used as a source for this instance
347 */
348
349 public byte[] getSource() {
350 return source;
351 }
352} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/util/io/HuffmanNode.java b/songdbj/de/jarnbjo/util/io/HuffmanNode.java
new file mode 100644
index 0000000000..88600a4ddd
--- /dev/null
+++ b/songdbj/de/jarnbjo/util/io/HuffmanNode.java
@@ -0,0 +1,144 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.2 2003/04/10 19:48:31 jarnbjo
25 * no message
26 *
27 */
28
29package de.jarnbjo.util.io;
30
31import java.io.IOException;
32import de.jarnbjo.util.io.BitInputStream;
33
34/**
35 * Representation of a node in a Huffman tree, used to read
36 * Huffman compressed codewords from e.g. a Vorbis stream.
37 */
38
39final public class HuffmanNode {
40
41 private HuffmanNode parent;
42 private int depth=0;
43 protected HuffmanNode o0, o1;
44 protected Integer value;
45 private boolean full=false;
46
47 /**
48 * creates a new Huffman tree root node
49 */
50
51 public HuffmanNode() {
52 this(null);
53 }
54
55 protected HuffmanNode(HuffmanNode parent) {
56 this.parent=parent;
57 if(parent!=null) {
58 depth=parent.getDepth()+1;
59 }
60 }
61
62 protected HuffmanNode(HuffmanNode parent, int value) {
63 this(parent);
64 this.value=new Integer(value);
65 full=true;
66 }
67
68 protected int read(BitInputStream bis) throws IOException {
69 HuffmanNode iter=this;
70 while(iter.value==null) {
71 iter=bis.getBit()?iter.o1:iter.o0;
72 }
73 return iter.value.intValue();
74 }
75
76 protected HuffmanNode get0() {
77 return o0==null?set0(new HuffmanNode(this)):o0;
78 }
79
80 protected HuffmanNode get1() {
81 return o1==null?set1(new HuffmanNode(this)):o1;
82 }
83
84 protected Integer getValue() {
85 return value;
86 }
87
88 private HuffmanNode getParent() {
89 return parent;
90 }
91
92 protected int getDepth() {
93 return depth;
94 }
95
96 private boolean isFull() {
97 return full?true:(full=o0!=null&&o0.isFull()&&o1!=null&&o1.isFull());
98 }
99
100 private HuffmanNode set0(HuffmanNode value) {
101 return o0=value;
102 }
103
104 private HuffmanNode set1(HuffmanNode value) {
105 return o1=value;
106 }
107
108 private void setValue(Integer value) {
109 full=true;
110 this.value=value;
111 }
112
113 /**
114 * creates a new tree node at the first free location at the given
115 * depth, and assigns the value to it
116 *
117 * @param depth the tree depth of the new node (codeword length in bits)
118 * @param value the node's new value
119 */
120
121 public boolean setNewValue(int depth, int value) {
122 if(isFull()) {
123 return false;
124 }
125 if(depth==1) {
126 if(o0==null) {
127 set0(new HuffmanNode(this, value));
128 return true;
129 }
130 else if(o1==null) {
131 set1(new HuffmanNode(this, value));
132 return true;
133 }
134 else {
135 return false;
136 }
137 }
138 else {
139 return get0().setNewValue(depth-1, value)?
140 true:
141 get1().setNewValue(depth-1, value);
142 }
143 }
144}