Compress.java revision 0
0N/A/*
0N/A * Copyright 1998-1999 Sun Microsystems, Inc. All Rights Reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
0N/A * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0N/A * CA 95054 USA or visit www.sun.com if you need additional information or
0N/A * have any questions.
0N/A */
0N/A
0N/A/*
0N/A */
0N/A
0N/Aimport java.io.*;
0N/Aimport java.rmi.server.*;
0N/Aimport java.net.*;
0N/A
0N/Apublic class Compress {
0N/A
0N/A interface CompressConstants {
0N/A // constants for 6-bit code values
0N/A static final int NOP = 0; // no operation: used to pad words on flush()
0N/A static final int RAW = 1; // introduces raw byte format
0N/A static final int BASE = 2; // base for codes found in lookup table
0N/A static final String codeTable =
0N/A "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ,.!?\"'()";
0N/A }
0N/A
0N/A public static class CompressRMIClientSocketFactory
0N/A implements java.rmi.server.RMIClientSocketFactory, Serializable {
0N/A
0N/A public Socket createSocket(String host, int port)
0N/A throws IOException {
0N/A
0N/A return ((Socket) new CompressSocket(host, port));
0N/A }
0N/A }
0N/A
0N/A public static class CompressRMIServerSocketFactory
0N/A implements RMIServerSocketFactory,
0N/A Serializable {
0N/A
0N/A public ServerSocket createServerSocket(int port)
0N/A throws IOException {
0N/A
0N/A return ((ServerSocket) new CompressServerSocket(port));
0N/A }
0N/A }
0N/A
0N/A public static class CompressSocket extends Socket {
0N/A private InputStream in;
0N/A private OutputStream out;
0N/A public CompressSocket() { super(); }
0N/A public CompressSocket(String host, int port) throws IOException {
0N/A super(host, port);
0N/A }
0N/A public InputStream getInputStream() throws IOException {
0N/A if (in == null) {
0N/A in = new CompressInputStream(super.getInputStream());
0N/A }
0N/A return in;
0N/A }
0N/A public OutputStream getOutputStream() throws IOException {
0N/A if (out == null) {
0N/A out = new CompressOutputStream(super.getOutputStream());
0N/A }
0N/A return out;
0N/A }
0N/A }
0N/A
0N/A public static class CompressServerSocket extends ServerSocket {
0N/A public CompressServerSocket(int port) throws IOException {
0N/A super(port);
0N/A }
0N/A public Socket accept() throws IOException {
0N/A Socket s = new CompressSocket();
0N/A implAccept(s);
0N/A return s;
0N/A }
0N/A }
0N/A
0N/A public static class CompressInputStream extends FilterInputStream
0N/A implements CompressConstants
0N/A {
0N/A
0N/A public CompressInputStream(InputStream in) {
0N/A super(in);
0N/A }
0N/A
0N/A // buffer of unpacked 6-bit codes from last 32-word read
0N/A int buf[] = new int[5];
0N/A
0N/A // position of next code to read in buffer (5 == end of buffer)
0N/A int bufPos = 5;
0N/A
0N/A public int read() throws IOException {
0N/A try {
0N/A int code;
0N/A do {
0N/A code = readCode();
0N/A } while (code == NOP); // ignore NOP codes
0N/A
0N/A if (code >= BASE)
0N/A return codeTable.charAt(code - BASE);
0N/A else if (code == RAW) {
0N/A int high = readCode();
0N/A int low = readCode();
0N/A return (high << 4) | low;
0N/A } else
0N/A throw new IOException("unknown compression code: " + code);
0N/A } catch (EOFException e) {
0N/A return -1;
0N/A }
0N/A }
0N/A
0N/A public int read(byte b[], int off, int len) throws IOException {
0N/A if (len <= 0) {
0N/A return 0;
0N/A }
0N/A
0N/A int c = read();
0N/A if (c == -1) {
0N/A return -1;
0N/A }
0N/A b[off] = (byte)c;
0N/A
0N/A int i = 1;
0N/A /*****
0N/A try {
0N/A for (; i < len ; i++) {
0N/A c = read();
0N/A if (c == -1) {
0N/A break;
0N/A }
0N/A if (b != null) {
0N/A b[off + i] = (byte)c;
0N/A }
0N/A }
0N/A } catch (IOException ee) {
0N/A }
0N/A *****/
0N/A return i;
0N/A }
0N/A
0N/A private int readCode() throws IOException {
0N/A if (bufPos == 5) {
0N/A int b1 = in.read();
0N/A int b2 = in.read();
0N/A int b3 = in.read();
0N/A int b4 = in.read();
0N/A if ((b1 | b2 | b3 | b4) < 0)
0N/A throw new EOFException();
0N/A int pack = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
0N/A buf[0] = (pack >>> 24) & 0x3F;
0N/A buf[1] = (pack >>> 18) & 0x3F;
0N/A buf[2] = (pack >>> 12) & 0x3F;
0N/A buf[3] = (pack >>> 6) & 0x3F;
0N/A buf[4] = (pack >>> 0) & 0x3F;
0N/A bufPos = 0;
0N/A }
0N/A return buf[bufPos++];
0N/A }
0N/A }
0N/A
0N/A public static class CompressOutputStream extends FilterOutputStream
0N/A implements CompressConstants
0N/A {
0N/A
0N/A public CompressOutputStream(OutputStream out) {
0N/A super(out);
0N/A }
0N/A
0N/A // buffer of 6-bit codes to pack into next 32-bit word
0N/A int buf[] = new int[5];
0N/A
0N/A // number of valid codes pending in buffer
0N/A int bufPos = 0;
0N/A
0N/A public void write(int b) throws IOException {
0N/A b &= 0xFF; // force argument to a byte
0N/A
0N/A int pos = codeTable.indexOf((char)b);
0N/A if (pos != -1)
0N/A writeCode(BASE + pos);
0N/A else {
0N/A writeCode(RAW);
0N/A writeCode(b >> 4);
0N/A writeCode(b & 0xF);
0N/A }
0N/A }
0N/A
0N/A public void write(byte b[], int off, int len) throws IOException {
0N/A /*
0N/A * This is quite an inefficient implementation, because it has to
0N/A * call the other write method for every byte in the array. It
0N/A * could be optimized for performance by doing all the processing
0N/A * in this method.
0N/A */
0N/A for (int i = 0; i < len; i++)
0N/A write(b[off + i]);
0N/A }
0N/A
0N/A public void flush() throws IOException {
0N/A while (bufPos > 0)
0N/A writeCode(NOP);
0N/A }
0N/A
0N/A private void writeCode(int c) throws IOException {
0N/A buf[bufPos++] = c;
0N/A if (bufPos == 5) { // write next word when we have 5 codes
0N/A int pack = (buf[0] << 24) | (buf[1] << 18) | (buf[2] << 12) |
0N/A (buf[3] << 6) | buf[4];
0N/A out.write((pack >>> 24) & 0xFF);
0N/A out.write((pack >>> 16) & 0xFF);
0N/A out.write((pack >>> 8) & 0xFF);
0N/A out.write((pack >>> 0) & 0xFF);
0N/A bufPos = 0;
0N/A }
0N/A }
0N/A }
0N/A}