| // |
| // Copyright (C) 2002 Constantin Kaplinsky. 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. |
| // |
| |
| // |
| // SessionRecorder is a class to write FBS (FrameBuffer Stream) files. |
| // FBS files are used to save RFB sessions for later playback. |
| // |
| |
| import java.io.*; |
| |
| class SessionRecorder { |
| |
| protected FileOutputStream f; |
| protected DataOutputStream df; |
| protected long startTime, lastTimeOffset; |
| |
| protected byte[] buffer; |
| protected int bufferSize; |
| protected int bufferBytes; |
| |
| public SessionRecorder(String name, int bufsize) throws IOException { |
| f = new FileOutputStream(name); |
| df = new DataOutputStream(f); |
| startTime = System.currentTimeMillis(); |
| lastTimeOffset = 0; |
| |
| bufferSize = bufsize; |
| bufferBytes = 0; |
| buffer = new byte[bufferSize]; |
| } |
| |
| public SessionRecorder(String name) throws IOException { |
| this(name, 65536); |
| } |
| |
| // |
| // Close the file, free resources. |
| // |
| |
| public void close() throws IOException { |
| try { |
| flush(); |
| } catch (IOException e) { |
| } |
| |
| df = null; |
| f.close(); |
| f = null; |
| buffer = null; |
| } |
| |
| // |
| // Write the FBS file header as defined in the rfbproxy utility. |
| // |
| |
| public void writeHeader() throws IOException { |
| df.write("FBS 001.000\n".getBytes()); |
| } |
| |
| // |
| // Write one byte. |
| // |
| |
| public void writeByte(int b) throws IOException { |
| prepareWriting(); |
| buffer[bufferBytes++] = (byte)b; |
| } |
| |
| // |
| // Write 16-bit value, big-endian. |
| // |
| |
| public void writeShortBE(int v) throws IOException { |
| prepareWriting(); |
| buffer[bufferBytes++] = (byte)(v >> 8); |
| buffer[bufferBytes++] = (byte)v; |
| } |
| |
| // |
| // Write 32-bit value, big-endian. |
| // |
| |
| public void writeIntBE(int v) throws IOException { |
| prepareWriting(); |
| buffer[bufferBytes] = (byte)(v >> 24); |
| buffer[bufferBytes + 1] = (byte)(v >> 16); |
| buffer[bufferBytes + 2] = (byte)(v >> 8); |
| buffer[bufferBytes + 3] = (byte)v; |
| bufferBytes += 4; |
| } |
| |
| // |
| // Write 16-bit value, little-endian. |
| // |
| |
| public void writeShortLE(int v) throws IOException { |
| prepareWriting(); |
| buffer[bufferBytes++] = (byte)v; |
| buffer[bufferBytes++] = (byte)(v >> 8); |
| } |
| |
| // |
| // Write 32-bit value, little-endian. |
| // |
| |
| public void writeIntLE(int v) throws IOException { |
| prepareWriting(); |
| buffer[bufferBytes] = (byte)v; |
| buffer[bufferBytes + 1] = (byte)(v >> 8); |
| buffer[bufferBytes + 2] = (byte)(v >> 16); |
| buffer[bufferBytes + 3] = (byte)(v >> 24); |
| bufferBytes += 4; |
| } |
| |
| // |
| // Write byte arrays. |
| // |
| |
| public void write(byte b[], int off, int len) throws IOException { |
| prepareWriting(); |
| while (len > 0) { |
| if (bufferBytes > bufferSize - 4) |
| flush(false); |
| |
| int partLen; |
| if (bufferBytes + len > bufferSize) { |
| partLen = bufferSize - bufferBytes; |
| } else { |
| partLen = len; |
| } |
| System.arraycopy(b, off, buffer, bufferBytes, partLen); |
| bufferBytes += partLen; |
| off += partLen; |
| len -= partLen; |
| } |
| } |
| |
| public void write(byte b[]) throws IOException { |
| write(b, 0, b.length); |
| } |
| |
| // |
| // Flush the output. This method saves buffered data in the |
| // underlying file object adding data sizes and timestamps. If the |
| // updateTimeOffset is set to false, then the current time offset |
| // will not be changed for next write operation. |
| // |
| |
| public void flush(boolean updateTimeOffset) throws IOException { |
| if (bufferBytes > 0) { |
| df.writeInt(bufferBytes); |
| df.write(buffer, 0, (bufferBytes + 3) & 0x7FFFFFFC); |
| df.writeInt((int)lastTimeOffset); |
| bufferBytes = 0; |
| if (updateTimeOffset) |
| lastTimeOffset = -1; |
| } |
| } |
| |
| public void flush() throws IOException { |
| flush(true); |
| } |
| |
| // |
| // Before writing any data, remember time offset and flush the |
| // buffer before it becomes full. |
| // |
| |
| protected void prepareWriting() throws IOException { |
| if (lastTimeOffset == -1) |
| lastTimeOffset = System.currentTimeMillis() - startTime; |
| if (bufferBytes > bufferSize - 4) |
| flush(false); |
| } |
| |
| } |
| |