1/*
2 * Copyright (c) 1998, 2008, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * 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}
235