blob: 67bcf970a0bf14dee869afd600fd57982f9e337b [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1998-1999 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 */
23
24/*
25 */
26
27import java.io.*;
28import java.rmi.server.*;
29import java.net.*;
30
31public class Compress {
32
33 interface CompressConstants {
34 // constants for 6-bit code values
35 static final int NOP = 0; // no operation: used to pad words on flush()
36 static final int RAW = 1; // introduces raw byte format
37 static final int BASE = 2; // base for codes found in lookup table
38 static final String codeTable =
39 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ,.!?\"'()";
40 }
41
42 public static class CompressRMIClientSocketFactory
43 implements java.rmi.server.RMIClientSocketFactory, Serializable {
44
45 public Socket createSocket(String host, int port)
46 throws IOException {
47
48 return ((Socket) new CompressSocket(host, port));
49 }
50 }
51
52 public static class CompressRMIServerSocketFactory
53 implements RMIServerSocketFactory,
54 Serializable {
55
56 public ServerSocket createServerSocket(int port)
57 throws IOException {
58
59 return ((ServerSocket) new CompressServerSocket(port));
60 }
61 }
62
63 public static class CompressSocket extends Socket {
64 private InputStream in;
65 private OutputStream out;
66 public CompressSocket() { super(); }
67 public CompressSocket(String host, int port) throws IOException {
68 super(host, port);
69 }
70 public InputStream getInputStream() throws IOException {
71 if (in == null) {
72 in = new CompressInputStream(super.getInputStream());
73 }
74 return in;
75 }
76 public OutputStream getOutputStream() throws IOException {
77 if (out == null) {
78 out = new CompressOutputStream(super.getOutputStream());
79 }
80 return out;
81 }
82 }
83
84 public static class CompressServerSocket extends ServerSocket {
85 public CompressServerSocket(int port) throws IOException {
86 super(port);
87 }
88 public Socket accept() throws IOException {
89 Socket s = new CompressSocket();
90 implAccept(s);
91 return s;
92 }
93 }
94
95 public static class CompressInputStream extends FilterInputStream
96 implements CompressConstants
97 {
98
99 public CompressInputStream(InputStream in) {
100 super(in);
101 }
102
103 // buffer of unpacked 6-bit codes from last 32-word read
104 int buf[] = new int[5];
105
106 // position of next code to read in buffer (5 == end of buffer)
107 int bufPos = 5;
108
109 public int read() throws IOException {
110 try {
111 int code;
112 do {
113 code = readCode();
114 } while (code == NOP); // ignore NOP codes
115
116 if (code >= BASE)
117 return codeTable.charAt(code - BASE);
118 else if (code == RAW) {
119 int high = readCode();
120 int low = readCode();
121 return (high << 4) | low;
122 } else
123 throw new IOException("unknown compression code: " + code);
124 } catch (EOFException e) {
125 return -1;
126 }
127 }
128
129 public int read(byte b[], int off, int len) throws IOException {
130 if (len <= 0) {
131 return 0;
132 }
133
134 int c = read();
135 if (c == -1) {
136 return -1;
137 }
138 b[off] = (byte)c;
139
140 int i = 1;
141 /*****
142 try {
143 for (; i < len ; i++) {
144 c = read();
145 if (c == -1) {
146 break;
147 }
148 if (b != null) {
149 b[off + i] = (byte)c;
150 }
151 }
152 } catch (IOException ee) {
153 }
154 *****/
155 return i;
156 }
157
158 private int readCode() throws IOException {
159 if (bufPos == 5) {
160 int b1 = in.read();
161 int b2 = in.read();
162 int b3 = in.read();
163 int b4 = in.read();
164 if ((b1 | b2 | b3 | b4) < 0)
165 throw new EOFException();
166 int pack = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
167 buf[0] = (pack >>> 24) & 0x3F;
168 buf[1] = (pack >>> 18) & 0x3F;
169 buf[2] = (pack >>> 12) & 0x3F;
170 buf[3] = (pack >>> 6) & 0x3F;
171 buf[4] = (pack >>> 0) & 0x3F;
172 bufPos = 0;
173 }
174 return buf[bufPos++];
175 }
176 }
177
178 public static class CompressOutputStream extends FilterOutputStream
179 implements CompressConstants
180 {
181
182 public CompressOutputStream(OutputStream out) {
183 super(out);
184 }
185
186 // buffer of 6-bit codes to pack into next 32-bit word
187 int buf[] = new int[5];
188
189 // number of valid codes pending in buffer
190 int bufPos = 0;
191
192 public void write(int b) throws IOException {
193 b &= 0xFF; // force argument to a byte
194
195 int pos = codeTable.indexOf((char)b);
196 if (pos != -1)
197 writeCode(BASE + pos);
198 else {
199 writeCode(RAW);
200 writeCode(b >> 4);
201 writeCode(b & 0xF);
202 }
203 }
204
205 public void write(byte b[], int off, int len) throws IOException {
206 /*
207 * This is quite an inefficient implementation, because it has to
208 * call the other write method for every byte in the array. It
209 * could be optimized for performance by doing all the processing
210 * in this method.
211 */
212 for (int i = 0; i < len; i++)
213 write(b[off + i]);
214 }
215
216 public void flush() throws IOException {
217 while (bufPos > 0)
218 writeCode(NOP);
219 }
220
221 private void writeCode(int c) throws IOException {
222 buf[bufPos++] = c;
223 if (bufPos == 5) { // write next word when we have 5 codes
224 int pack = (buf[0] << 24) | (buf[1] << 18) | (buf[2] << 12) |
225 (buf[3] << 6) | buf[4];
226 out.write((pack >>> 24) & 0xFF);
227 out.write((pack >>> 16) & 0xFF);
228 out.write((pack >>> 8) & 0xFF);
229 out.write((pack >>> 0) & 0xFF);
230 bufPos = 0;
231 }
232 }
233 }
234}