1 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
2  * Copyright (C) 2011-2019 Brian P. Hinz
3  *
4  * This is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This software is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this software; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
17  * USA.
18  */
19 
20 //
21 // rdr::OutStream marshalls data into a buffer stored in RDR (RFB Data
22 // Representation).
23 //
24 
25 package com.tigervnc.rdr;
26 
27 import java.nio.*;
28 
29 import com.tigervnc.network.*;
30 
31 abstract public class OutStream {
32 
33   // check() ensures there is buffer space for at least one item of size
34   // itemSize bytes.  Returns the number of items which fit (up to a maximum
35   // of nItems).
36 
check(int itemSize, int nItems)37   public final int check(int itemSize, int nItems) {
38     int nAvail;
39 
40     if (itemSize > (end - ptr))
41       return overrun(itemSize, nItems);
42 
43     nAvail = (end - ptr) / itemSize;
44     if (nAvail < nItems)
45       return nAvail;
46 
47     return nItems;
48   }
49 
check(int itemSize)50   public final void check(int itemSize) {
51     if (ptr + itemSize > end)
52       overrun(itemSize, 1);
53   }
54 
55   // writeU/SN() methods write unsigned and signed N-bit integers.
56 
writeU8( int u)57   public final void writeU8( int u) { check(1); b[ptr++] = (byte)u; }
writeU16(int u)58   public final void writeU16(int u) { check(2); b[ptr++] = (byte)(u >> 8);
59                                       b[ptr++] = (byte)u; }
writeU32(int u)60   public final void writeU32(int u) { check(4); b[ptr++] = (byte)(u >> 24);
61                                       b[ptr++] = (byte)(u >> 16);
62                                       b[ptr++] = (byte)(u >> 8);
63                                       b[ptr++] = (byte)u; }
64 
writeS8( int s)65   public final void writeS8( int s) { writeU8( s); }
writeS16(int s)66   public final void writeS16(int s) { writeU16(s); }
writeS32(int s)67   public final void writeS32(int s) { writeU32(s); }
68 
69   // writeCompactLength() writes 1..3 bytes representing length of the data
70   // following.  This method is used by the Tight encoder.
71 
writeCompactLength(int len)72   public final void writeCompactLength(int len) {
73     byte b = (byte)(len & 0x7F);
74     if (len <= 0x7F) {
75       writeU8(b);
76     } else {
77       writeU8(b | 0x80);
78       b = (byte)(len >> 7 & 0x7F);
79       if (len <= 0x3FFF) {
80         writeU8(b);
81       } else {
82         writeU8(b | 0x80);
83         writeU8(len >> 14 & 0xFF);
84       }
85     }
86   }
87 
88   // writeString() writes a string - a U32 length followed by the data.
89 
writeString(String str)90   public final void writeString(String str) {
91     int len = str.length();
92     writeU32(len);
93     try {
94       byte[] utf8str = str.getBytes("UTF8");
95       writeBytes(utf8str, 0, len);
96     } catch(java.io.UnsupportedEncodingException e) {
97       e.printStackTrace();
98     }
99   }
100 
pad(int bytes)101   public final void pad(int bytes) {
102     while (bytes-- > 0) writeU8(0);
103   }
104 
skip(int bytes)105   public final void skip(int bytes) {
106     while (bytes > 0) {
107       int n = check(1, bytes);
108       ptr += n;
109       bytes -= n;
110     }
111   }
112 
113   // writeBytes() writes an exact number of bytes from an array at an offset.
114 
writeBytes(byte[] data, int dataPtr, int length)115   public void writeBytes(byte[] data, int dataPtr, int length) {
116     int dataEnd = dataPtr + length;
117     while (dataPtr < dataEnd) {
118       int n = check(1, dataEnd - dataPtr);
119       System.arraycopy(data, dataPtr, b, ptr, n);
120       ptr += n;
121       dataPtr += n;
122     }
123   }
124 
writeBytes(ByteBuffer data, int length)125   public void writeBytes(ByteBuffer data, int length) {
126     while (length > 0) {
127       int n = check(1, length);
128       data.get(b, ptr, n);
129       ptr += n;
130       length -= n;
131     }
132   }
133 
134   // copyBytes() efficiently transfers data between streams
135 
copyBytes(InStream is, int length)136   public void copyBytes(InStream is, int length) {
137     while (length > 0) {
138       int n = check(1, length);
139       is.readBytes(ByteBuffer.wrap(b, ptr, n), n);
140       ptr += n;
141       length -= n;
142     }
143   }
144 
145   // writeOpaqueN() writes a quantity without byte-swapping.  Because java has
146   // no byte-ordering, we just use big-endian.
147 
writeOpaque8( int u)148   public final void writeOpaque8( int u) { writeU8( u); }
writeOpaque16(int u)149   public final void writeOpaque16(int u) { writeU16(u); }
writeOpaque32(int u)150   public final void writeOpaque32(int u) { writeU32(u); }
writeOpaque24A(int u)151   public final void writeOpaque24A(int u) { check(3);
152                                             b[ptr++] = (byte)(u >> 24);
153                                             b[ptr++] = (byte)(u >> 16);
154                                             b[ptr++] = (byte)(u >> 8); }
writeOpaque24B(int u)155   public final void writeOpaque24B(int u) { check(3);
156                                             b[ptr++] = (byte)(u >> 16);
157                                             b[ptr++] = (byte)(u >> 8);
158                                             b[ptr++] = (byte)u; }
159 
160   // length() returns the length of the stream.
161 
length()162   abstract public int length();
163 
164   // flush() requests that the stream be flushed.
165 
flush()166   public void flush() {}
167 
168   // getptr(), getend() and setptr() are "dirty" methods which allow you to
169   // manipulate the buffer directly.  This is useful for a stream which is a
170   // wrapper around an underlying stream.
171 
getbuf()172   public final byte[] getbuf() { return b; }
getptr()173   public final int getptr() { return ptr; }
getend()174   public final int getend() { return end; }
setptr(int p)175   public final void setptr(int p) { ptr = p; }
176 
177   // overrun() is implemented by a derived class to cope with buffer overrun.
178   // It ensures there are at least itemSize bytes of buffer space.  Returns
179   // the number of items which fit (up to a maximum of nItems).  itemSize is
180   // supposed to be "small" (a few bytes).
181 
overrun(int itemSize, int nItems)182   abstract protected int overrun(int itemSize, int nItems);
183 
OutStream()184   protected OutStream() {}
185   protected byte[] b;
186   protected int ptr;
187   protected int end;
188 }
189