diff options
Diffstat (limited to 'java/src/com/tigervnc/rdr')
-rw-r--r-- | java/src/com/tigervnc/rdr/EndOfStream.java | 25 | ||||
-rw-r--r-- | java/src/com/tigervnc/rdr/Exception.java | 25 | ||||
-rw-r--r-- | java/src/com/tigervnc/rdr/IOException.java | 27 | ||||
-rw-r--r-- | java/src/com/tigervnc/rdr/InStream.java | 196 | ||||
-rw-r--r-- | java/src/com/tigervnc/rdr/JavaInStream.java | 147 | ||||
-rw-r--r-- | java/src/com/tigervnc/rdr/JavaOutStream.java | 82 | ||||
-rw-r--r-- | java/src/com/tigervnc/rdr/MemInStream.java | 34 | ||||
-rw-r--r-- | java/src/com/tigervnc/rdr/MemOutStream.java | 53 | ||||
-rw-r--r-- | java/src/com/tigervnc/rdr/OutStream.java | 141 | ||||
-rw-r--r-- | java/src/com/tigervnc/rdr/ZlibInStream.java | 113 |
10 files changed, 843 insertions, 0 deletions
diff --git a/java/src/com/tigervnc/rdr/EndOfStream.java b/java/src/com/tigervnc/rdr/EndOfStream.java new file mode 100644 index 00000000..bdcf7c27 --- /dev/null +++ b/java/src/com/tigervnc/rdr/EndOfStream.java @@ -0,0 +1,25 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +package com.tigervnc.rdr; + +public class EndOfStream extends Exception { + public EndOfStream() { + super("EndOfStream"); + } +} diff --git a/java/src/com/tigervnc/rdr/Exception.java b/java/src/com/tigervnc/rdr/Exception.java new file mode 100644 index 00000000..a5fe938d --- /dev/null +++ b/java/src/com/tigervnc/rdr/Exception.java @@ -0,0 +1,25 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +package com.tigervnc.rdr; + +public class Exception extends RuntimeException { + public Exception(String s) { + super(s); + } +} diff --git a/java/src/com/tigervnc/rdr/IOException.java b/java/src/com/tigervnc/rdr/IOException.java new file mode 100644 index 00000000..6343d7a4 --- /dev/null +++ b/java/src/com/tigervnc/rdr/IOException.java @@ -0,0 +1,27 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +package com.tigervnc.rdr; + +class IOException extends Exception { + public IOException(java.io.IOException ex_) { + super(ex_.toString()); + ex = ex_; + } + java.io.IOException ex; +} diff --git a/java/src/com/tigervnc/rdr/InStream.java b/java/src/com/tigervnc/rdr/InStream.java new file mode 100644 index 00000000..ec2d6d7c --- /dev/null +++ b/java/src/com/tigervnc/rdr/InStream.java @@ -0,0 +1,196 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +// +// rdr::InStream marshalls data from a buffer stored in RDR (RFB Data +// Representation). +// + +package com.tigervnc.rdr; + +abstract public class InStream { + + // check() ensures there is buffer data for at least one item of size + // itemSize bytes. Returns the number of items in the buffer (up to a + // maximum of nItems). + + public int check(int itemSize, int nItems) { + if (ptr + itemSize * nItems > end) { + if (ptr + itemSize > end) + return overrun(itemSize, nItems); + + nItems = (end - ptr) / itemSize; + } + return nItems; + } + + public final int check(int itemSize) { + if (ptr + itemSize > end) + return overrun(itemSize, 1); + return 1; + } + + // checkNoWait() tries to make sure that the given number of bytes can + // be read without blocking. It returns true if this is the case, false + // otherwise. The length must be "small" (less than the buffer size). + + public final boolean checkNoWait(int length) { return check(length, 1)!=0; } + + // readU/SN() methods read unsigned and signed N-bit integers. + + public final int readS8() { check(1); return b[ptr++]; } + public final int readS16() { check(2); int b0 = b[ptr++]; + int b1 = b[ptr++] & 0xff; return b0 << 8 | b1; } + public final int readS32() { check(4); int b0 = b[ptr++]; + int b1 = b[ptr++] & 0xff; + int b2 = b[ptr++] & 0xff; + int b3 = b[ptr++] & 0xff; + return b0 << 24 | b1 << 16 | b2 << 8 | b3; } + + public final int readU8() { return readS8() & 0xff; } + public final int readU16() { return readS16() & 0xffff; } + public final int readU32() { return readS32() & 0xffffffff; } + + // readString() reads a string - a U32 length followed by the data. + + public final String readString() { + int len = readU32(); + if (len > maxStringLength) + throw new Exception("InStream max string length exceeded"); + + char[] str = new char[len]; + int i = 0; + while (i < len) { + int j = i + check(1, len - i); + while (i < j) { + str[i++] = (char)b[ptr++]; + } + } + + return new String(str); + } + + // maxStringLength protects against allocating a huge buffer. Set it + // higher if you need longer strings. + + public static int maxStringLength = 65535; + + public final void skip(int bytes) { + while (bytes > 0) { + int n = check(1, bytes); + ptr += n; + bytes -= n; + } + } + + // readBytes() reads an exact number of bytes into an array at an offset. + + public void readBytes(byte[] data, int offset, int length) { + int offsetEnd = offset + length; + while (offset < offsetEnd) { + int n = check(1, offsetEnd - offset); + System.arraycopy(b, ptr, data, offset, n); + ptr += n; + offset += n; + } + } + + public void readBytes(int[] data, int offset, int length) { + int offsetEnd = offset + length; + while (offset < offsetEnd) { + int n = check(1, offsetEnd - offset); + System.arraycopy(b, ptr, data, offset, n); + ptr += n; + offset += n; + } + } + + // readOpaqueN() reads a quantity "without byte-swapping". Because java has + // no byte-ordering, we just use big-endian. + + public final int readOpaque8() { return readU8(); } + public final int readOpaque16() { return readU16(); } + public final int readOpaque32() { return readU32(); } + public final int readOpaque24A() { check(3); int b0 = b[ptr++]; + int b1 = b[ptr++]; int b2 = b[ptr++]; + return b0 << 24 | b1 << 16 | b2 << 8; } + public final int readOpaque24B() { check(3); int b0 = b[ptr++]; + int b1 = b[ptr++]; int b2 = b[ptr++]; + return b0 << 16 | b1 << 8 | b2; } + + public final int readPixel(int bytesPerPixel, boolean e) { + int[] pix = new int[4]; + for (int i=0; i < bytesPerPixel; i++) + pix[i] = readU8(); + if (e) { + return pix[0] << 16 | pix[1] << 8 | pix[2] | (0xff << 24); + } else { + return pix[2] << 16 | pix[1] << 8 | pix[0] | (0xff << 24); + } + } + + public final void readPixels(int[] buf, int length, int bytesPerPixel, boolean e) { + for (int i = 0; i < length; i++) + buf[i] = readPixel(bytesPerPixel, e); + } + + public final int readCompactLength() { + int b = readU8(); + int result = b & 0x7F; + if ((b & 0x80) != 0) { + b = readU8(); + result |= (b & 0x7F) << 7; + if ((b & 0x80) != 0) { + b = readU8(); + result |= (b & 0xFF) << 14; + } + } + return result; + } + + // pos() returns the position in the stream. + + abstract public int pos(); + + // bytesAvailable() returns true if at least one byte can be read from the + // stream without blocking. i.e. if false is returned then readU8() would + // block. + + public boolean bytesAvailable() { return end != ptr; } + + // getbuf(), getptr(), getend() and setptr() are "dirty" methods which allow + // you to manipulate the buffer directly. This is useful for a stream which + // is a wrapper around an underlying stream. + + public final byte[] getbuf() { return b; } + public final int getptr() { return ptr; } + public final int getend() { return end; } + public final void setptr(int p) { ptr = p; } + + // overrun() is implemented by a derived class to cope with buffer overrun. + // It ensures there are at least itemSize bytes of buffer data. Returns + // the number of items in the buffer (up to a maximum of nItems). itemSize + // is supposed to be "small" (a few bytes). + + abstract protected int overrun(int itemSize, int nItems); + + protected InStream() {} + protected byte[] b; + protected int ptr; + protected int end; +} diff --git a/java/src/com/tigervnc/rdr/JavaInStream.java b/java/src/com/tigervnc/rdr/JavaInStream.java new file mode 100644 index 00000000..426a0e76 --- /dev/null +++ b/java/src/com/tigervnc/rdr/JavaInStream.java @@ -0,0 +1,147 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +// +// A JavaInStream reads from a java.io.InputStream +// + +package com.tigervnc.rdr; + +public class JavaInStream extends InStream { + + static final int defaultBufSize = 8192; + static final int minBulkSize = 1024; + + public JavaInStream(java.io.InputStream jis_, int bufSize_) { + jis = jis_; + bufSize = bufSize_; + b = new byte[bufSize]; + ptr = end = ptrOffset = 0; + timeWaitedIn100us = 5; + timedKbits = 0; + } + + public JavaInStream(java.io.InputStream jis_) { this(jis_, defaultBufSize); } + + public void readBytes(byte[] data, int offset, int length) { + if (length < minBulkSize) { + super.readBytes(data, offset, length); + return; + } + + int n = end - ptr; + if (n > length) n = length; + + System.arraycopy(b, ptr, data, offset, n); + offset += n; + length -= n; + ptr += n; + + while (length > 0) { + n = read(data, offset, length); + offset += n; + length -= n; + ptrOffset += n; + } + } + + public int pos() { return ptrOffset + ptr; } + + public void startTiming() { + timing = true; + + // Carry over up to 1s worth of previous rate for smoothing. + + if (timeWaitedIn100us > 10000) { + timedKbits = timedKbits * 10000 / timeWaitedIn100us; + timeWaitedIn100us = 10000; + } + } + + public void stopTiming() { + timing = false; + if (timeWaitedIn100us < timedKbits/2) + timeWaitedIn100us = timedKbits/2; // upper limit 20Mbit/s + } + + public long kbitsPerSecond() { + return timedKbits * 10000 / timeWaitedIn100us; + } + + public long timeWaited() { return timeWaitedIn100us; } + + protected int overrun(int itemSize, int nItems) { + if (itemSize > bufSize) + throw new Exception("JavaInStream overrun: max itemSize exceeded"); + + if (end - ptr != 0) + System.arraycopy(b, ptr, b, 0, end - ptr); + + ptrOffset += ptr; + end -= ptr; + ptr = 0; + + while (end < itemSize) { + int n = read(b, end, bufSize - end); + end += n; + } + + if (itemSize * nItems > end) + nItems = end / itemSize; + + return nItems; + } + + private int read(byte[] buf, int offset, int len) { + try { + long before = 0; + if (timing) + before = System.currentTimeMillis(); + + int n = jis.read(buf, offset, len); + if (n < 0) throw new EndOfStream(); + + if (timing) { + long after = System.currentTimeMillis(); + long newTimeWaited = (after - before) * 10; + int newKbits = n * 8 / 1000; + + // limit rate to between 10kbit/s and 40Mbit/s + + if (newTimeWaited > newKbits*1000) newTimeWaited = newKbits*1000; + if (newTimeWaited < newKbits/4) newTimeWaited = newKbits/4; + + timeWaitedIn100us += newTimeWaited; + timedKbits += newKbits; + } + + return n; + + } catch (java.io.IOException e) { + throw new IOException(e); + } + } + + private java.io.InputStream jis; + private int ptrOffset; + private int bufSize; + + boolean timing; + long timeWaitedIn100us; + long timedKbits; +} diff --git a/java/src/com/tigervnc/rdr/JavaOutStream.java b/java/src/com/tigervnc/rdr/JavaOutStream.java new file mode 100644 index 00000000..94791b9d --- /dev/null +++ b/java/src/com/tigervnc/rdr/JavaOutStream.java @@ -0,0 +1,82 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +// +// A JavaOutStream writes to a java.io.OutputStream +// + +package com.tigervnc.rdr; + +public class JavaOutStream extends OutStream { + + static final int defaultBufSize = 16384; + static final int minBulkSize = 1024; + + public JavaOutStream(java.io.OutputStream jos_, int bufSize_) { + jos = jos_; + bufSize = bufSize_; + b = new byte[bufSize]; + ptr = 0; + end = bufSize; + } + + public JavaOutStream(java.io.OutputStream jos) { this(jos, defaultBufSize); } + + public void writeBytes(byte[] data, int offset, int length) { + if (length < minBulkSize) { + super.writeBytes(data, offset, length); + return; + } + + flush(); + try { + jos.write(data, offset, length); + } catch (java.io.IOException e) { + throw new IOException(e); + } + ptrOffset += length; + } + + public void flush() { + try { + jos.write(b, 0, ptr); + } catch (java.io.IOException e) { + throw new IOException(e); + } + ptrOffset += ptr; + ptr = 0; + } + + public int length() { return ptrOffset + ptr; } + + protected int overrun(int itemSize, int nItems) { + if (itemSize > bufSize) + throw new Exception("JavaOutStream overrun: max itemSize exceeded"); + + flush(); + + if (itemSize * nItems > end) + nItems = end / itemSize; + + return nItems; + } + + private java.io.OutputStream jos; + private int ptrOffset; + private int bufSize; +} diff --git a/java/src/com/tigervnc/rdr/MemInStream.java b/java/src/com/tigervnc/rdr/MemInStream.java new file mode 100644 index 00000000..ce4f91e3 --- /dev/null +++ b/java/src/com/tigervnc/rdr/MemInStream.java @@ -0,0 +1,34 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +package com.tigervnc.rdr; + +public class MemInStream extends InStream { + + public MemInStream(byte[] data, int offset, int len) { + b = data; + ptr = offset; + end = offset + len; + } + + public int pos() { return ptr; } + + protected int overrun(int itemSize, int nItems) { + throw new EndOfStream(); + } +} diff --git a/java/src/com/tigervnc/rdr/MemOutStream.java b/java/src/com/tigervnc/rdr/MemOutStream.java new file mode 100644 index 00000000..b3040793 --- /dev/null +++ b/java/src/com/tigervnc/rdr/MemOutStream.java @@ -0,0 +1,53 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +// +// A MemOutStream grows as needed when data is written to it. +// + +package com.tigervnc.rdr; + +public class MemOutStream extends OutStream { + + public MemOutStream(int len) { + b = new byte[len]; + ptr = 0; + end = len; + } + public MemOutStream() { this(1024); } + + public int length() { return ptr; } + public void clear() { ptr = 0; }; + public void reposition(int pos) { ptr = pos; } + + // overrun() either doubles the buffer or adds enough space for nItems of + // size itemSize bytes. + + protected int overrun(int itemSize, int nItems) { + int len = ptr + itemSize * nItems; + if (len < end * 2) + len = end * 2; + + byte[] newBuf = new byte[len]; + System.arraycopy(b, 0, newBuf, 0, ptr); + b = newBuf; + end = len; + + return nItems; + } +} diff --git a/java/src/com/tigervnc/rdr/OutStream.java b/java/src/com/tigervnc/rdr/OutStream.java new file mode 100644 index 00000000..7b4869e0 --- /dev/null +++ b/java/src/com/tigervnc/rdr/OutStream.java @@ -0,0 +1,141 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +// +// rdr::OutStream marshalls data into a buffer stored in RDR (RFB Data +// Representation). +// + +package com.tigervnc.rdr; + +abstract public class OutStream { + + // check() ensures there is buffer space for at least one item of size + // itemSize bytes. Returns the number of items which fit (up to a maximum + // of nItems). + + public final int check(int itemSize, int nItems) { + if (ptr + itemSize * nItems > end) { + if (ptr + itemSize > end) + return overrun(itemSize, nItems); + + nItems = (end - ptr) / itemSize; + } + return nItems; + } + + public final void check(int itemSize) { + if (ptr + itemSize > end) + overrun(itemSize, 1); + } + + // writeU/SN() methods write unsigned and signed N-bit integers. + + public final void writeU8( int u) { check(1); b[ptr++] = (byte)u; } + public final void writeU16(int u) { check(2); b[ptr++] = (byte)(u >> 8); + b[ptr++] = (byte)u; } + public final void writeU32(int u) { check(4); b[ptr++] = (byte)(u >> 24); + b[ptr++] = (byte)(u >> 16); + b[ptr++] = (byte)(u >> 8); + b[ptr++] = (byte)u; } + + public final void writeS8( int s) { writeU8( s); } + public final void writeS16(int s) { writeU16(s); } + public final void writeS32(int s) { writeU32(s); } + + // writeString() writes a string - a U32 length followed by the data. + + public final void writeString(String str) { + int len = str.length(); + writeU32(len); + for (int i = 0; i < len;) { + int j = i + check(1, len - i); + while (i < j) { + b[ptr++] = (byte)str.charAt(i++); + } + } + } + + public final void pad(int bytes) { + while (bytes-- > 0) writeU8(0); + } + + public final void skip(int bytes) { + while (bytes > 0) { + int n = check(1, bytes); + ptr += n; + bytes -= n; + } + } + + // writeBytes() writes an exact number of bytes from an array at an offset. + + public void writeBytes(byte[] data, int offset, int length) { + int offsetEnd = offset + length; + while (offset < offsetEnd) { + int n = check(1, offsetEnd - offset); + System.arraycopy(data, offset, b, ptr, n); + ptr += n; + offset += n; + } + } + + // writeOpaqueN() writes a quantity without byte-swapping. Because java has + // no byte-ordering, we just use big-endian. + + public final void writeOpaque8( int u) { writeU8( u); } + public final void writeOpaque16(int u) { writeU16(u); } + public final void writeOpaque32(int u) { writeU32(u); } + public final void writeOpaque24A(int u) { check(3); + b[ptr++] = (byte)(u >> 24); + b[ptr++] = (byte)(u >> 16); + b[ptr++] = (byte)(u >> 8); } + public final void writeOpaque24B(int u) { check(3); + b[ptr++] = (byte)(u >> 16); + b[ptr++] = (byte)(u >> 8); + b[ptr++] = (byte)u; } + + // length() returns the length of the stream. + + abstract public int length(); + + // flush() requests that the stream be flushed. + + public void flush() {} + + // getptr(), getend() and setptr() are "dirty" methods which allow you to + // manipulate the buffer directly. This is useful for a stream which is a + // wrapper around an underlying stream. + + public final byte[] getbuf() { return b; } + public final int getptr() { return ptr; } + public final int getend() { return end; } + public final void setptr(int p) { ptr = p; } + + // overrun() is implemented by a derived class to cope with buffer overrun. + // It ensures there are at least itemSize bytes of buffer space. Returns + // the number of items which fit (up to a maximum of nItems). itemSize is + // supposed to be "small" (a few bytes). + + abstract protected int overrun(int itemSize, int nItems); + + protected OutStream() {} + protected byte[] b; + protected int ptr; + protected int end; +} diff --git a/java/src/com/tigervnc/rdr/ZlibInStream.java b/java/src/com/tigervnc/rdr/ZlibInStream.java new file mode 100644 index 00000000..64de00a1 --- /dev/null +++ b/java/src/com/tigervnc/rdr/ZlibInStream.java @@ -0,0 +1,113 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +// +// A ZlibInStream reads from a zlib.io.InputStream +// + +package com.tigervnc.rdr; + +public class ZlibInStream extends InStream { + + static final int defaultBufSize = 16384; + + public ZlibInStream(int bufSize_) { + bufSize = bufSize_; + b = new byte[bufSize]; + ptr = end = ptrOffset = 0; + inflater = new java.util.zip.Inflater(); + } + + public ZlibInStream() { this(defaultBufSize); } + + public void setUnderlying(InStream is, int bytesIn_) { + underlying = is; + bytesIn = bytesIn_; + ptr = end = 0; + } + + public void reset() { + ptr = end = 0; + if (underlying == null) return; + + while (bytesIn > 0) { + decompress(); + end = 0; // throw away any data + } + underlying = null; + } + + public int pos() { return ptrOffset + ptr; } + + protected int overrun(int itemSize, int nItems) { + if (itemSize > bufSize) + throw new Exception("ZlibInStream overrun: max itemSize exceeded"); + if (underlying == null) + throw new Exception("ZlibInStream overrun: no underlying stream"); + + if (end - ptr != 0) + System.arraycopy(b, ptr, b, 0, end - ptr); + + ptrOffset += ptr; + end -= ptr; + ptr = 0; + + while (end < itemSize) { + decompress(); + } + + if (itemSize * nItems > end) + nItems = end / itemSize; + + return nItems; + } + + // decompress() calls the decompressor once. Note that this won't + // necessarily generate any output data - it may just consume some input + // data. Returns false if wait is false and we would block on the underlying + // stream. + + private void decompress() { + try { + underlying.check(1); + int avail_in = underlying.getend() - underlying.getptr(); + if (avail_in > bytesIn) + avail_in = bytesIn; + + if (inflater.needsInput()) { + inflater.setInput(underlying.getbuf(), underlying.getptr(), avail_in); + } + + int n = inflater.inflate(b, end, bufSize - end); + + end += n; + if (inflater.needsInput()) { + bytesIn -= avail_in; + underlying.setptr(underlying.getptr() + avail_in); + } + } catch (java.util.zip.DataFormatException e) { + throw new Exception("ZlibInStream: inflate failed"); + } + } + + private InStream underlying; + private int bufSize; + private int ptrOffset; + private java.util.zip.Inflater inflater; + private int bytesIn; +} |