OutputStreamWrapper.java
// Copyright (c) ZeroC, Inc.
package com.zeroc.Ice;
import java.io.IOException;
import java.io.OutputStream;
//
// Class to provide a java.io.OutputStream on top of our stream.
// We use this to serialize arbitrary Java serializable classes into
//
// Slice sequences are encoded on the wire as a count of elements, followed
// by the sequence contents. For arbitrary Java classes, we do not know how
// big the sequence that is eventually written will be. To avoid excessive
// data copying, this class mantains a private _bytes array of 254 bytes and,
// initially, writes data into that array. If more than 254 bytes end up being
// written, we write a dummy sequence size of 255 (which occupies five bytes
// on the wire) into the stream and, once this stream is closed, patch
// that size to match the actual size. Otherwise, if the _bytes buffer contains
// fewer than 255 bytes when this stream is closed, we write the sequence size
// as a single byte, followed by the contents of the _bytes buffer.
//
class OutputStreamWrapper extends OutputStream {
public OutputStreamWrapper(com.zeroc.Ice.OutputStream s) {
_s = s;
_spos = s.pos();
_bytes = new byte[254];
_pos = 0;
}
@Override
public void write(int b) throws IOException {
try {
if (_bytes != null) {
//
// If we can fit the data into the first 254 bytes, write it to _bytes.
//
if (_pos < _bytes.length) {
_bytes[_pos++] = (byte) b;
return;
}
_s.writeSize(255); // Dummy size, until we know how big the stream
// really is and can patch the size.
if (_pos > 0) {
//
// Write the current contents of _bytes.
//
_s.expand(_pos);
_s.getBuffer().b.put(_bytes, 0, _pos);
}
_bytes = null;
}
//
// Write data passed by caller.
//
_s.expand(1);
_s.getBuffer().b.put((byte) b);
_pos += 1;
} catch (Exception ex) {
throw new IOException(ex.toString());
}
}
@Override
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
@Override
public void write(byte[] bytes, int offset, int count) throws IOException {
try {
if (_bytes != null) {
//
// If we can fit the data into the first 254 bytes, write it to _bytes.
//
if (count <= _bytes.length - _pos) {
System.arraycopy(bytes, offset, _bytes, _pos, count);
_pos += count;
return;
}
_s.writeSize(255); // Dummy size, until we know how big the stream
// really is and can patch the size.
if (_pos > 0) {
//
// Write the current contents of _bytes.
//
_s.expand(_pos);
_s.getBuffer().b.put(_bytes, 0, _pos);
}
_bytes = null;
}
//
// Write data passed by caller.
//
_s.expand(count);
_s.getBuffer().b.put(bytes, offset, count);
_pos += count;
} catch (Exception ex) {
throw new IOException(ex.toString());
}
}
@Override
public void flush() throws IOException {
// This does nothing because we do not know the final size of a writable stream until it is
// closed, and we cannot write to the stream until we know whether the final size is < 255
// or not.
}
@Override
public void close() throws IOException {
try {
if (_bytes != null) {
assert (_pos <= _bytes.length);
_s.pos(_spos);
_s.writeSize(_pos);
_s.expand(_pos);
_s.getBuffer().b.put(_bytes, 0, _pos);
_bytes = null;
} else {
int currentPos = _s.pos();
_s.pos(_spos);
_s.writeSize(_pos); // Patch previously-written dummy value.
_s.pos(currentPos);
}
} catch (Exception ex) {
throw new IOException(ex.toString());
}
}
private final com.zeroc.Ice.OutputStream _s;
private final int _spos;
private byte[] _bytes;
private int _pos;
}