1 /* ZNet - Java Compression Layer for a new Socket Factory
2 Copyright (C) 1999, Free Software Rulez
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18 The author of this program may be contacted at morgiaclaudio@yahoo.it. */
19
20 package java.net;
21
22 import java.lang;
23 import java.io;
24
25 /**
26 * This class implements a <b>growing</b> ByteArrayInputStream. Normally a ByteArrayInputStream is initialized
27 * and cannot change its internal byte array.
28 * This class provides a method to add byte arrays to the internal buffer thus enlarging it dynamically.
29 * Moreover, this class provides an efficient garbage collector that shrink the internal byte array
30 * as data gets read, preventing memory trashing!
31 * @see #run the main loop
32 * @see java.io.ByteArrayInputStream
33 * @author <a href="mailto:morgiaclaudio@yahoo.it">Claudio Morgia</a>
34 * @version 1.0
35 */
36 public class ZInputStream extends ByteArrayInputStream {
37
38 /**
39 * This empty constructor builds an object with a preallocated buffer.
40 */
41 public ZInputStream() {
42 super(new byte[100]);
43 count=0;
44 }
45
46 /**
47 * This constructor builds an object that initially contains the byte array passed as argument.
48 * @param b the initial byte array data buffer
49 */
50 public ZInputStream(byte[] b) {
51 super(b);
52 }
53
54 /**
55 * This constructor builds an object that initially contains the byte array passed as argument,
56 * starting from an offset and going for a limited extent, as specified by the second and third
57 * argument.
58 * @param b the initial byte array data buffer
59 * @param off the offset form which to start
60 * @param len the byte array extent to consider
61 */
62 public ZInputStream(byte[] b,int off,int len) {
63 super(b,off,len);
64 }
65
66 /**
67 * This method adds a byte array to the internal buffer thus enlarging it.
68 * The singularity is that it uses an internal garbage collector to ensure that the
69 * buffer size is always the minimum to contain the unread data but never contains read data
70 * that occupies memory with old useless data!
71 * @param b the byte array to add
72 */
73 public void addBytes(byte[] b) {
74 byte[] _buf;
75 if (count!=0 && buf.length-count<b.length)
76 gc();
77 if (buf.length-count<b.length) {
78 _buf=new byte[buf.length+b.length];
79 System.arraycopy(buf,0,_buf,0,count);
80 System.arraycopy(b,0,_buf,count,b.length);
81 buf=_buf;
82 count+=b.length;
83 } else {
84 System.arraycopy(b,0,buf,count,b.length);
85 count+=b.length;
86 }
87 }
88
89 /**
90 * This method reads a single int from the uderlying input stream.
91 * The <i>"waiting for available data"</i> situation has been realized using an uncommon waiting loop:<br>
92 * <code>while (<condition>) Thread.yield(); </code><br>
93 * that's far more efficient than the usual one:<br>
94 * <code>while (<condition>) ; </code>
95 * @return the integer read
96 */
97 public synchronized int read() {
98 while (count<1)
99 Thread.yield();
100 return super.read();
101 }
102
103 /**
104 * This method reads an array of bytes storing into a specified byte array, starting from an offset
105 * and going for a specified number of bytes.
106 * The <i>"waiting for available data"</i> situation has been realized using an uncommon waiting loop:<br>
107 * <code>while (<condition>) Thread.yield(); </code><br>
108 * that's far more efficient than the usual one:<br>
109 * <code>while (<condition>) ; </code>
110 * @param b the byte array to use as buffer
111 * @param off the offset to use as a starting point
112 * @param len the number of bytes to read
113 */
114 public synchronized int read(byte b[], int off, int len) {
115 while (count<1)
116 Thread.yield();
117 return super.read(b,off,len);
118 }
119
120 /**
121 * This method resets the underlying input stream.
122 * @see java.io.ByteArrayInputStream#reset
123 */
124 public void reset() {
125 super.reset();
126 }
127
128 /**
129 * This little garbage collector, if invoked, moves the internal buffer towards the start,
130 * if some read but unfreed data exists, even if the read and unread region overlaps.
131 * And it's composed of only three instructions!
132 */
133 protected void gc() {
134 System.arraycopy(buf,pos,buf,0,count-pos+1);
135 count-=pos-1;
136 pos=0;
137 }
138
139 /**
140 * Internal use only.
141 */
142 public void dump() {
143 D.p("count= "+count+"\nposition= "+pos);
144 }
145 }