KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > sapia > ubik > util > ByteVector


1 package org.sapia.ubik.util;
2
3 import java.io.IOException JavaDoc;
4 import java.io.OutputStream JavaDoc;
5 import java.nio.ByteBuffer JavaDoc;
6
7 /**
8  * This class can conveniently be used as a replacement for the JDK's
9  * <code>ByteArrayInputStream</code> and <code>ByteArrayOutputStream</code>
10  * classes.
11  * <p>
12  * This class implements a vector of byte arrays (it encapsulates an array of
13  * byte arrays). An instance of this class will "grow" (according to a predefined
14  * increment) as new bytes are added to it (and if its current size does not allow
15  * for these new bytes to fit in).
16  * <p>
17  * In addition, each byte array that is internally kept (and stores the actual
18  * bytes written to this instance) is created with a fixed capacity (which can
19  * be specified when creating an instance of this class).
20  * <p>
21  * An instance of this class internally keeps track of its current position in
22  * the vector. That position is incremented according to the reads and writes that
23  * are performed. Thus, existing bytes are not overwritten and are not read twice.
24  * <p>
25  * An instance of this class can be reused without destroying the internal byte
26  * arrays that have been created. Similarly, reading bytes from the instance
27  * does not require copying the whole bytes that the instance stores to an
28  * intermediary array that is returned to the caller - instead, this instance
29  * directly supports reads (this is a workaround to the JDK's ByteArrayOutputStream
30  * class and its <code>toByteArray()</code> method.
31  * <p>
32  * <b>WARNING: THIS CLASS IS NOT THREAD-SAFE</b>.
33  *
34  *
35  * @author Yanick Duchesne
36  *
37  * @see ByteVectorInputStream
38  * @see ByteVectorOutputStream
39  *
40  * <dl>
41  * <dt><b>Copyright:</b><dd>Copyright &#169; 2002-2005 <a HREF="http://www.sapia-oss.org">Sapia Open Source Software</a>. All Rights Reserved.</dd></dt>
42  * <dt><b>License:</b><dd>Read the license.txt file of the jar or visit the
43  * <a HREF="http://www.sapia-oss.org/license.html">license page</a> at the Sapia OSS web site</dd></dt>
44  * </dl>
45  */

46 public class ByteVector {
47   
48   public static final int DEFAULT_ARRAY_CAPACITY = 200;
49   public static final int DEFAULT_INCREMENT = 10;
50   
51   private int _arrayPos, _markPos, _markOffset, _arrayCount;
52   private int _capacity = DEFAULT_ARRAY_CAPACITY;
53   private int _increment = DEFAULT_INCREMENT;
54   
55   private ByteArray[] _arrays = new ByteArray[_increment];
56
57   /**
58    * Creates an instance of this class with the default capacity and increment.
59    */

60   public ByteVector(){}
61   
62   /**
63    * Creates an instance of this class with the given capacity and increment.
64    * The capacity corresponds to the size of the internal bytes arrays (that are
65    * created to store data). The increment corresponds to the amount of internal
66    * byte arrays that will be created when this instance will grow.
67    *
68    * @param capacity some capacity.
69    * @param increment some increment.
70    */

71   public ByteVector(int capacity, int increment){
72     _capacity = capacity;
73     _increment = increment;
74   }
75   
76   
77   /**
78    * Internally sets the given position as a mark. The internal position counter
79    * will internally be set to that mark upon the <code>reset</code> method
80    * being called.
81    *
82    * @param mark some mark.
83    * @see #reset()
84    */

85   public void mark(int mark){
86     if(mark < _capacity){
87       _markPos = 0;
88       _markOffset = mark;
89     }
90     else{
91       int pos = mark/_capacity;
92       int offset = mark%_capacity;
93       if(pos >= _arrayCount){
94         throw new IndexOutOfBoundsException JavaDoc(""+mark);
95       }
96       _markPos = pos;
97       _markOffset = offset;
98     }
99   }
100   
101   /**
102    * Resets the internal position to the specified mark. The position will be
103    * set to 0 if no mark has been specified.
104    *
105    * @see #mark(int)
106    */

107   public void reset(){
108     _arrayPos = _markPos;
109     _arrays[_arrayPos]._pos = _markOffset;
110     for(int i = _arrayPos+1; i < _arrayCount; i++){
111       _arrays[i]._pos = 0;
112     }
113   }
114   
115   /**
116    * Clears the data that this instance holds, making it suitable for reuse.
117    *
118    * @param freeMemory if <code>true</code>, the internal byte arrays that have
119    * been created will be dereferenced (otherwise, they will be reused).
120    */

121   public void clear(boolean freeMemory){
122     _arrayPos = 0;
123     _markOffset = 0;
124     _markPos = 0;
125     if(freeMemory){
126       _arrays = new ByteArray[_increment];
127     }
128     else{
129       for(int i = 0; i < _arrayCount; i++){
130         _arrays[i]._pos = 0;
131         _arrays[i]._limit = 0;
132       }
133     }
134     _arrayCount = 0;
135   }
136
137   /**
138    * Returns the number of bytes that this instance holds.
139    */

140   public int length(){
141     if(_arrayCount == 0){
142       return 0;
143     }
144     return (_arrayCount-1)*_capacity+_arrays[_arrayCount-1]._limit;
145   }
146   
147   /**
148    * @return the current internal position of this instance, in terms of the
149    * bytes it holds.
150    */

151   public int position(){
152     if(_arrayCount == 0){
153       return 0;
154     }
155     else if(_arrayPos == 0){
156       return _arrays[_arrayPos]._pos;
157     }
158     if(_arrayPos >= _arrayCount){
159       return (_arrayCount-1) * _capacity + _arrays[_arrayCount-1]._pos;
160     }
161     else{
162       return _arrayPos * _capacity + _arrays[_arrayPos]._pos;
163     }
164   }
165   
166   /**
167    * Returns the number of remaining bytes in this instance.
168    *
169    * @return <code>lenth() - position()</code>
170    */

171   public int remaining(){
172     return length() - position();
173   }
174   
175   int arrayPosition(){
176     return _arrayPos;
177   }
178   
179   int arrayCount(){
180     return _arrayCount;
181   }
182   
183   /**
184    * @return <code>true</code> if this instance's current internal position is
185    * less than the number of bytes it holds.
186    */

187   public boolean hasRemaining(){
188     return _arrayPos < _arrayCount && _arrays[_arrayPos]._pos < _arrays[_arrayPos]._limit;
189   }
190   
191   /**
192    * Returns the bytes that this instance holds (starting from this instance's
193    * current position).
194    */

195   public byte[] toByteArray(){
196     if(_arrayCount == 0 || _arrays[0] == null){
197       return new byte[0];
198     }
199     byte[] b = new byte[length()];
200     int index = 0;
201     for(int i = _arrayPos; i < _arrayCount; i++){
202       for(int j = 0; j < _arrays[i]._limit; j++){
203         b[index] = _arrays[i]._bytes[j];
204         index++;
205       }
206     }
207     return b;
208   }
209   
210   /**
211    * @return the next byte that this instance holds, or <code>-1</code>
212    * if this instance holds no more bytes.
213    */

214   public int read(){
215     if(_arrayCount == 0 || _arrayPos >= _arrayCount){
216       return -1;
217     }
218     ByteArray arr = _arrays[_arrayPos];
219     if(arr == null) return -1;
220     if(arr._pos < arr._limit){
221       int b = arr._bytes[arr._pos++] & 0xff;
222       if(arr._pos >= arr._limit){
223         _arrayPos++;
224       }
225       return b;
226     }
227     return -1;
228   }
229   
230   /**
231    * @param b a byte array that will be filled with the bytes that were read.
232    *
233    * @return the number of bytes that were read.
234    */

235   public int read(byte[] b){
236     return read(b, 0, b.length);
237   }
238   
239   /**
240    * @param b a byte array that will be filled with the bytes that were read.
241    * @off the offset from which bytes should be inserted into the given array.
242    * @len the number of bytes to fill in the given array, starting from the
243    * given offset.
244    * @return the number of bytes that were read.
245    */

246   public int read(byte[] b, int off, int len){
247     int read = 0;
248     int total = 0;
249     while(len > 0 && _arrayPos < _arrayCount){
250       read = _arrays[_arrayPos].get(b, off, len);
251       if(read == 0){
252         break;
253       }
254       if(_arrays[_arrayPos]._pos >= _arrays[_arrayPos]._limit){
255         _arrayPos++;
256       }
257       len = len - read;
258       off = off + read;
259       total += read;
260     }
261     return total;
262   }
263   
264   /**
265    * @param a <code>ByteBuffer</code>.
266    * @return the number of bytes that were read.
267    */

268   public int read(ByteBuffer JavaDoc buf){
269     int read = 0;
270     int total = 0;
271     int len = buf.remaining();
272     while(len > 0 && _arrayPos < _arrayCount){
273       read = _arrays[_arrayPos].get(buf, len);
274       if(read == 0){
275         break;
276       }
277       if(_arrays[_arrayPos]._pos >= _arrays[_arrayPos]._limit){
278         _arrayPos++;
279       }
280       len = len - read;
281       total += read;
282     }
283     return total;
284     
285   }
286   
287   /**
288    * Reads this instance's bytes and transfers them to the given stream.
289    *
290    * @param out an <code>OutputStream</code>.
291    */

292   public void read(OutputStream JavaDoc out) throws IOException JavaDoc{
293     int read;
294     while(_arrayPos < _arrayCount){
295       read = _arrays[_arrayPos].get(out);
296       if(read == 0){
297         break;
298       }
299       if(_arrays[_arrayPos]._pos >= _arrays[_arrayPos]._limit){
300         _arrayPos++;
301       }
302     }
303   }
304   
305   /**
306    * Writes the given bytes to this instance.
307    *
308    * @param b the array of bytes to write.
309    */

310   public void write(byte[] b){
311     write(b, 0, b.length);
312   }
313   
314   public void write(int b){
315     if(_arrayPos >= _arrayCount)
316       increase();
317     if(!_arrays[_arrayPos++].put((byte)b)){
318       increase();
319       _arrays[_arrayPos-1].put((byte)b);
320     }
321   }
322   
323   /**
324    * Writes the given bytes to this instance.
325    *
326    * @param b the array of bytes to write.
327    * @param off the offset from which to start taking the bytes in the given
328    * array.
329    * @param len the number of bytes to read, starting from the given offset.
330    */

331   public void write(byte[] b, int off, int len){
332     int put = 0;
333     while(put < len){
334       if(_arrayPos >= _arrayCount){
335         increase();
336       }
337       put = _arrays[_arrayPos].put(b, off, len);
338       if(put < len){
339         _arrayPos++;
340       }
341       off += put;
342       len -= put;
343       put = 0;
344     }
345   }
346   
347   /**
348    * Writes the bytes contained in the given buffer to this instance.
349    *
350    * @param buf a <code>ByteBuffer</code>
351    */

352   public void write(ByteBuffer JavaDoc buf){
353     while(buf.hasRemaining()){
354       if(_arrayPos >= _arrayCount){
355         increase();
356       }
357       int len = buf.remaining();
358       int put = _arrays[_arrayPos].put(buf);
359       if(put < len){
360         _arrayPos++;
361       }
362       put = 0;
363     }
364   }
365   
366   /**
367    * Skips the number of bytes within this instance.
368    *
369    * @return the number of bytes that were actually skipped.
370    */

371   public long skip(long skip){
372     if(_arrayCount == 0){
373       return 0;
374     }
375     long total = 0;
376     while(total < skip && _arrayPos < _arrayCount){
377       ByteArray arr = _arrays[_arrayPos];
378       
379       if(arr == null)
380         break;
381       
382       int size = arr._limit - arr._pos;
383       
384       if(size <= 0)
385         break;
386       
387       if(total + size <= skip){
388         arr._pos = arr._limit;
389         total = total + size;
390         _arrayPos++;
391       }
392       else{
393         size = (int)(skip - total);
394         arr._pos = arr._pos + size;
395         total = total + size;
396       }
397     }
398     return total;
399   }
400   
401   private void increase(){
402     if(_arrayPos >= _arrays.length){
403       ByteArray[] newArray = new ByteArray[_arrays.length+_increment];
404       System.arraycopy(_arrays, 0, newArray, 0, _arrays.length);
405       _arrays = newArray;
406     }
407     if(_arrays[_arrayPos] == null){
408       _arrays[_arrayPos] = new ByteArray(_capacity);
409     }
410     _arrayCount++;
411   }
412   
413   ///////////////////////// ByteArray ///////////////////////////
414

415   static class ByteArray{
416     int _pos;
417     int _limit;
418     byte[] _bytes;
419     ByteArray(int capacity){
420       _bytes = new byte[capacity];
421     }
422
423     boolean put(byte b){
424       if(_pos < _bytes.length){
425         _bytes[_pos++] = b;
426         _limit++;
427       }
428       return false;
429     }
430     
431     int put(byte[] b, int offset, int len){
432       if(_pos < _bytes.length){
433         if(len <= _bytes.length - _pos){
434           System.arraycopy(b, offset, _bytes, _pos, len);
435           _pos += len;
436           _limit += len;
437           return len;
438         }
439         else{
440           System.arraycopy(b, offset, _bytes, _pos, _bytes.length - _pos);
441           int put = _bytes.length - _pos;
442           _pos += put;
443           _limit += put;
444           return put;
445         }
446       }
447       return 0;
448     }
449     
450     int put(ByteBuffer JavaDoc buf){
451       if(_pos < _bytes.length){
452         if(buf.remaining() <= _bytes.length - _pos){
453           int len = buf.remaining();
454           buf.get(_bytes, _pos, buf.remaining());
455           _pos += len;
456           _limit += len;
457           return len;
458         }
459         else{
460           buf.get(_bytes, _pos, _bytes.length - _pos);
461           int put = _bytes.length - _pos;
462           _pos += put;
463           _limit += put;
464           return put;
465         }
466       }
467       return 0;
468     }
469     
470     int get(byte[] b, int offset, int len){
471       if(_pos < _limit){
472         if(_limit - _pos <= len){
473           System.arraycopy(_bytes, _pos, b, offset, _limit - _pos);
474           int read = _limit - _pos;
475           _pos += read;
476           return read;
477         }
478         else{
479           System.arraycopy(_bytes, _pos, b, offset, len);
480           _pos += len;
481           return len;
482         }
483       }
484       return 0;
485     }
486     
487     int get(ByteBuffer JavaDoc buf, int len){
488       if(_pos < _limit){
489         if(_limit - _pos <= len){
490           buf.put(_bytes, _pos, _limit - _pos);
491           int read = _limit - _pos;
492           _pos += read;
493           return read;
494         }
495         else{
496           buf.put(_bytes, _pos, len);
497           _pos += len;
498           return len;
499         }
500       }
501       return 0;
502     }
503     
504     int get(OutputStream JavaDoc out) throws IOException JavaDoc{
505       if(_pos >= _limit){
506         return 0;
507       }
508       out.write(_bytes, _pos, _limit);
509       int read = _limit - _pos;
510       _pos = _pos + read;
511       return read;
512     }
513   }
514
515 }
516
Popular Tags