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