todo lists for configuration
[invirt/packages/invirt-vnc-client.git] / SessionRecorder.java
1 //
2 //  Copyright (C) 2002 Constantin Kaplinsky.  All Rights Reserved.
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
17 //  USA.
18 //
19
20 //
21 // SessionRecorder is a class to write FBS (FrameBuffer Stream) files.
22 // FBS files are used to save RFB sessions for later playback.
23 //
24
25 import java.io.*;
26
27 class SessionRecorder {
28
29   protected FileOutputStream f;
30   protected DataOutputStream df;
31   protected long startTime, lastTimeOffset;
32
33   protected byte[] buffer;
34   protected int bufferSize;
35   protected int bufferBytes;
36
37   public SessionRecorder(String name, int bufsize) throws IOException {
38     f = new FileOutputStream(name);
39     df = new DataOutputStream(f);
40     startTime = System.currentTimeMillis();
41     lastTimeOffset = 0;
42     
43     bufferSize = bufsize;
44     bufferBytes = 0;
45     buffer = new byte[bufferSize];
46   }
47
48   public SessionRecorder(String name) throws IOException {
49     this(name, 65536);
50   }
51
52   //
53   // Close the file, free resources.
54   //
55
56   public void close() throws IOException {
57     try {
58       flush();
59     } catch (IOException e) {
60     }
61
62     df = null;
63     f.close();
64     f = null;
65     buffer = null;
66   }
67
68   //
69   // Write the FBS file header as defined in the rfbproxy utility.
70   //
71
72   public void writeHeader() throws IOException {
73     df.write("FBS 001.000\n".getBytes());
74   }
75
76   //
77   // Write one byte.
78   //
79
80   public void writeByte(int b) throws IOException {
81     prepareWriting();
82     buffer[bufferBytes++] = (byte)b;
83   }
84
85   //
86   // Write 16-bit value, big-endian.
87   //
88
89   public void writeShortBE(int v) throws IOException {
90     prepareWriting();
91     buffer[bufferBytes++] = (byte)(v >> 8);
92     buffer[bufferBytes++] = (byte)v;
93   }
94
95   //
96   // Write 32-bit value, big-endian.
97   //
98
99   public void writeIntBE(int v) throws IOException {
100     prepareWriting();
101     buffer[bufferBytes]     = (byte)(v >> 24);
102     buffer[bufferBytes + 1] = (byte)(v >> 16);
103     buffer[bufferBytes + 2] = (byte)(v >> 8);
104     buffer[bufferBytes + 3] = (byte)v;
105     bufferBytes += 4;
106   }
107
108   //
109   // Write 16-bit value, little-endian.
110   //
111
112   public void writeShortLE(int v) throws IOException {
113     prepareWriting();
114     buffer[bufferBytes++] = (byte)v;
115     buffer[bufferBytes++] = (byte)(v >> 8);
116   }
117
118   //
119   // Write 32-bit value, little-endian.
120   //
121
122   public void writeIntLE(int v) throws IOException {
123     prepareWriting();
124     buffer[bufferBytes]     = (byte)v;
125     buffer[bufferBytes + 1] = (byte)(v >> 8);
126     buffer[bufferBytes + 2] = (byte)(v >> 16);
127     buffer[bufferBytes + 3] = (byte)(v >> 24);
128     bufferBytes += 4;
129   }
130
131   //
132   // Write byte arrays.
133   //
134
135   public void write(byte b[], int off, int len) throws IOException {
136     prepareWriting();
137     while (len > 0) {
138       if (bufferBytes > bufferSize - 4)
139         flush(false);
140
141       int partLen;
142       if (bufferBytes + len > bufferSize) {
143         partLen = bufferSize - bufferBytes;
144       } else {
145         partLen = len;
146       }
147       System.arraycopy(b, off, buffer, bufferBytes, partLen);
148       bufferBytes += partLen;
149       off += partLen;
150       len -= partLen;
151     }
152   }
153
154   public void write(byte b[]) throws IOException {
155     write(b, 0, b.length);
156   }
157
158   //
159   // Flush the output. This method saves buffered data in the
160   // underlying file object adding data sizes and timestamps. If the
161   // updateTimeOffset is set to false, then the current time offset
162   // will not be changed for next write operation.
163   //
164
165   public void flush(boolean updateTimeOffset) throws IOException {
166     if (bufferBytes > 0) {
167       df.writeInt(bufferBytes);
168       df.write(buffer, 0, (bufferBytes + 3) & 0x7FFFFFFC);
169       df.writeInt((int)lastTimeOffset);
170       bufferBytes = 0;
171       if (updateTimeOffset)
172         lastTimeOffset = -1;
173     }
174   }
175
176   public void flush() throws IOException {
177     flush(true);
178   }
179
180   //
181   // Before writing any data, remember time offset and flush the
182   // buffer before it becomes full.
183   //
184
185   protected void prepareWriting() throws IOException {
186     if (lastTimeOffset == -1)
187       lastTimeOffset = System.currentTimeMillis() - startTime;
188     if (bufferBytes > bufferSize - 4)
189       flush(false);
190   }
191
192 }
193