Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/anotherbigidea/io/OutStream.java


1   /****************************************************************
2    * Copyright (c) 2001, David N. Main, All rights reserved.
3    * 
4    * Redistribution and use in source and binary forms, with or
5    * without modification, are permitted provided that the 
6    * following conditions are met:
7    *
8    * 1. Redistributions of source code must retain the above 
9    * copyright notice, this list of conditions and the following 
10   * disclaimer. 
11   * 
12   * 2. Redistributions in binary form must reproduce the above 
13   * copyright notice, this list of conditions and the following 
14   * disclaimer in the documentation and/or other materials 
15   * provided with the distribution.
16   * 
17   * 3. The name of the author may not be used to endorse or 
18   * promote products derived from this software without specific 
19   * prior written permission. 
20   * 
21   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY 
22   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
23   * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
24   * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
25   * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
26   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
27   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
28   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
29   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
30   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
31   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
32   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33   ****************************************************************/
34  package com.anotherbigidea.io;
35  
36  import java.io.ByteArrayOutputStream;
37  import java.io.DataOutputStream;
38  import java.io.IOException;
39  import java.io.OutputStream;
40  import java.util.zip.Deflater;
41  import java.util.zip.DeflaterOutputStream;
42  
43  /**
44   * Output Stream Wrapper
45   */
46  public class OutStream extends OutputStreamWrapper
47  {
48    //--Bit buffer..
49    private int mBitBuf;
50    private int mBitPos;
51      
52    public OutStream( OutputStream out )
53    {
54      super( out );
55          
56      initBits();
57    }
58  
59    protected OutStream() {
60      super(null);
61    }
62  
63    /**
64     * Write a signed value to the output stream in the given number of bits.
65     * The value must actually fit in that number of bits or it will be garbled
66     */
67    public void writeSBits( int numBits, int value ) throws IOException 
68    {
69      //--Mask out any sign bit
70      long lval = value & 0x7FFFFFFF;
71          
72      if( value < 0 ) //add the sign bit
73      {
74        lval |= 1L << (numBits-1);
75      }
76          
77      //--Write the bits as if unsigned
78      writeUBits( numBits, lval );
79    }
80      
81    public void flush() throws IOException
82    {
83      flushBits();
84      super.flush();
85    }
86      
87    /**
88     * Compress all subsequent data
89     */
90    public void writeCompressed() {
91      setOutputStream( new DeflaterOutputStream( getOutputStream(), 
92               new Deflater( Deflater.BEST_COMPRESSION )));
93    }
94      
95    /**
96     * Flush the bit buffer to the output stream and reset values
97     */
98    public void flushBits() throws IOException
99    {
100     if( mBitPos == 0 ) return;  //nothing to flush
101         
102     super.write( mBitBuf );
103     mBitBuf = 0;
104     mBitPos = 0;
105   }
106     
107   /**
108    * Write an unsigned value to the output stream in the given number of bits
109    */
110   public void writeUBits( int numBits, long value ) throws IOException 
111   {   
112     if( numBits == 0 ) return;
113         
114     if( mBitPos == 0 ) mBitPos = 8;  //bitBuf was empty
115         
116     int bitNum = numBits;
117         
118     while( bitNum > 0 )  //write all bits
119     {
120       while( mBitPos > 0 && bitNum > 0 ) //write into all position of the bit buffer
121       {
122         if( getBit( bitNum, value ) ) mBitBuf = setBit( mBitPos, mBitBuf );
123                 
124         bitNum--;
125         mBitPos--;
126       }
127             
128       if( mBitPos == 0 ) //bit buffer is full - write it
129       {
130         writeUI8( mBitBuf );
131         mBitBuf = 0;
132         if( bitNum > 0 ) mBitPos = 8; //prepare for more bits
133       }
134     }
135   }
136         
137     
138   /**
139    * Get the given bit (where lowest bit is numbered 1)
140    */
141   public static boolean getBit( int bitNum, long value )
142   {
143     return (value & (1L << (bitNum - 1))) != 0;
144   }
145     
146   /**
147    * Set the given bit (where lowest bit is numbered 1)
148    */    
149   public static int setBit( int bitNum, int value )
150   {
151     return value | ( 1 << (bitNum-1) );
152   }    
153     
154   /**
155    * Write the given bytes to the output stream
156    */
157   public void write( byte[] bytes ) throws IOException
158   {
159     flushBits();
160         
161     if( bytes != null && bytes.length > 0 )
162     {
163       super.write( bytes );
164     }
165   }
166 
167   /**
168    * Write the given bytes to the output stream
169    */
170   public void write( byte[] bytes, int start, int length ) throws IOException
171   {
172     flushBits();
173         
174     if( bytes != null && length > 0 )
175     {
176       super.write( bytes, start, length );
177     }
178   }    
179     
180   /**
181    * Write an 8 bit unsigned value to the out stream
182    */
183   public void writeUI8( int value ) throws IOException
184   {
185     flushBits();
186         
187     super.write( value  );
188   }  
189     
190   /**
191    * Write a 16 bit unsigned value to the out stream
192    */
193   public void writeUI16( int value ) throws IOException
194   {
195     flushBits();
196         
197     super.write( value & 0xff );
198     super.write( value >> 8   );
199   }
200 
201   /**
202    * Write a 16 bit signed value to the out stream
203    */
204   public void writeSI16( short value ) throws IOException
205   {
206     flushBits();
207         
208     super.write( value & 0xff );
209     super.write( value >> 8 );
210   }
211     
212     
213   /**
214    * Write a 32 bit unsigned value to the out stream
215    */
216   public void writeUI32( long value ) throws IOException
217   {
218     flushBits();
219         
220     super.write( (int)( value & 0xff ) );
221     super.write( (int)( value >>  8  ) );
222     super.write( (int)( value >> 16  ) );
223     super.write( (int)( value >> 24  ) );
224   }  
225     
226   /**
227    * Write a string to the output stream using the default encoding and add terminating null
228    */
229   public void writeString( String s, String encoding ) throws IOException 
230   {
231     if( s == null ) s = "";
232     writeString( s.getBytes( encoding ) );
233   }
234     
235   /**
236    * Write a string to the output stream and add terminating null
237    */
238   public void writeString( byte[] string ) throws IOException 
239   {
240     flushBits();
241         
242     if( string != null ) super.write( string );
243     super.write( 0 );  //terminate string
244   }   
245     
246   /**
247    * Calculate the byte length of a string as it would be written to the
248    * output stream
249    */
250   public static int getStringLength( byte[] string )
251   {
252     if( string == null ) return 1;
253     return string.length + 1; //to include the terminating null
254   }
255 
256   /**
257    * Calculate the byte length of a string as it would be written to the
258    * output stream using the default character encoding
259    */
260   public static int getStringLength( String string )
261   {
262     if( string == null ) return 1;
263     byte[] bytes = string.getBytes();
264         
265     return bytes.length + 1; //to include the terminating null
266   }    
267     
268   /**
269    * Reset the bit buffer
270    */
271   private void initBits()
272   {
273     mBitBuf = 0;
274     mBitPos = 0;
275   }
276     
277   /**
278    * Determine the minimum number of bits required to hold the given
279    * signed value
280    */
281   public static int determineSignedBitSize( int value )
282   {
283     if( value >= 0 ) return determineUnsignedBitSize( value ) + 1;
284         
285     //--This is probably a really bad way of doing this...
286     int  topBit = 31;
287     long mask = 0x40000000L;
288         
289     while( topBit > 0 )
290     {
291       if( (value & mask) == 0 ) break;
292             
293       mask >>= 1;
294       topBit--;
295     }
296         
297     if( topBit == 0 ) return 2;  //must have been -1
298         
299     //HACK: Flash represents -16 as 110000 rather than 10000 etc..
300     int val2 = value & (( 1 << topBit) - 1 );
301     if( val2 == 0 )
302     {
303       topBit++;
304     }
305         
306     return topBit + 1;
307   }
308 
309   /**
310    * Determine the minimum number of bits required to hold the given
311    * unsigned value (may be zero)
312    */
313   public static int determineUnsignedBitSize( long value )
314   {
315     //--This is probably a really bad way of doing this...
316     int  topBit = 32;
317     long mask = 0x80000000L;
318         
319     while( topBit > 0 )
320     {
321       if( (value & mask) != 0 ) return topBit;
322             
323       mask >>= 1;
324       topBit--;
325     }
326         
327     return 0;
328   }
329     
330   /**
331    * Write a float value
332    */
333   public void writeFloat( float value ) throws IOException
334   {
335     writeSI32( Float.floatToIntBits( value ) );
336   }
337     
338   /**
339    * Write a double value
340    */
341   public void writeDouble( double value ) throws IOException
342   {
343     ByteArrayOutputStream baos = new ByteArrayOutputStream();
344     DataOutputStream dout = new DataOutputStream( baos );
345         
346     dout.writeDouble( value );
347         
348     dout.flush();
349         
350     byte[] bytes = baos.toByteArray();
351     byte[] bytes2 = new byte[8];
352         
353     bytes2[0] = bytes[3];
354     bytes2[1] = bytes[2];
355     bytes2[2] = bytes[1];
356     bytes2[3] = bytes[0];
357     bytes2[4] = bytes[7];
358     bytes2[5] = bytes[6];
359     bytes2[6] = bytes[5];
360     bytes2[7] = bytes[4];        
361         
362     write( bytes2 );
363   }
364     
365   /**
366    * Write a 32 bit signed value
367    */
368   public void writeSI32( int value ) throws IOException 
369   {
370     flushBits();
371         
372     super.write( value & 0xff );
373     super.write( value >> 8 );
374     super.write( value >> 16 );
375     super.write( value >> 24 );
376   }
377     
378   /**
379    * Util to convert a signed int to 2 bytes
380    */
381   public static byte[] sintTo2Bytes( int value )
382   {
383     return new byte[]
384     {
385       uintToByte( value & 0xff ),
386       uintToByte( value >> 8   )
387     };
388   }
389     
390   /**
391    * Util to convert an unsigned int to 2 bytes
392    */
393   public static byte[] uintTo2Bytes( int value )
394   {
395     return new byte[]
396     {
397       uintToByte( value & 0xff ),
398       uintToByte( value >> 8   )
399     };
400   }
401 
402   /**
403    * Util to convert an unsigned int to 4 bytes
404    */
405   public static byte[] uintTo4Bytes( int value )
406   {
407     return new byte[]
408     {
409       uintToByte( value & 0xff ),
410       uintToByte( value >> 8   ),
411       uintToByte( value >> 16  ),
412       uintToByte( value >> 24  )
413     };
414   }    
415     
416   /**
417    * Util to convert an unsigned int to an unsigned byte
418    */
419   public static byte uintToByte( int value )
420   {
421     int lowbit = value & 1;
422     value >>= 1;
423         
424     byte b = (byte)value;
425     b <<= 1;
426     b |= (byte)lowbit;
427         
428     return b;
429   }  
430     
431   /**
432    * @see java.io.OutputStream#write(int)
433    */
434   public void write( int b ) throws IOException {
435     flushBits();
436     super.write( b );
437   }
438   
439   /**
440    * Override to ensure that bits are flushed
441    */
442   public void close() throws IOException {
443     flush();
444     super.close();
445   }
446 
447 }