J. Duke | 319a3b9 | 2007-12-01 00:00:00 +0000 | [diff] [blame^] | 1 | /* |
| 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 | |
| 27 | import java.io.*; |
| 28 | import java.rmi.server.*; |
| 29 | import java.net.*; |
| 30 | |
| 31 | public 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 | } |