org.firebirdsql.gds.impl.wire.XdrOutputStream Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jaybird Show documentation
Show all versions of jaybird Show documentation
JDBC Driver for the Firebird RDBMS
/*
* Firebird Open Source J2ee connector - jdbc driver
*
* Distributable under LGPL license.
* You may obtain a copy of the License at http://www.gnu.org/copyleft/lgpl.html
*
* This program 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
* LGPL License for more details.
*
* This file was created by members of the firebird development team.
* All individual contributions remain the Copyright (C) of those
* individuals. Contributors to this file are either listed here or
* can be obtained from a CVS history command.
*
* All rights reserved.
*/
/*
* The Original Code is the Firebird Java GDS implementation.
*
* The Initial Developer of the Original Code is Alejandro Alberola.
* Portions created by Alejandro Alberola are Copyright (C) 2001
* Boix i Oltra, S.L. All Rights Reserved.
*/
package org.firebirdsql.gds.impl.wire;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import org.firebirdsql.gds.ISCConstants;
import org.firebirdsql.gds.XSQLDA;
import org.firebirdsql.gds.XSQLVAR;
import org.firebirdsql.logging.Logger;
import org.firebirdsql.logging.LoggerFactory;
/**
* An XdrOutputStream
writes data in XDR format to an
* underlying java.io.OutputStream
.
*
* @author Alejandro Alberola
* @author David Jencks
* @version 1.0
*/
public class XdrOutputStream {
private static final int BUF_SIZE = 32767;
private static Logger log = LoggerFactory.getLogger(XdrOutputStream.class,false);
private static byte[] textPad = new byte[BUF_SIZE];
private static byte[] zero = new XSQLVAR().encodeInt(0); // todo
private static byte[] minusOne = new XSQLVAR().encodeInt(-1);
private byte[] buf = new byte[BUF_SIZE];
private int count;
private OutputStream out = null;
protected XdrOutputStream() {
// empty, for subclasses.
}
/**
* Create a new instance of XdrOutputStream
.
*
* @param out The underlying OutputStream
to write to
*/
public XdrOutputStream(OutputStream out) {
this.out = out;
count=0;
// fill the padding with blanks
Arrays.fill(textPad,(byte) 32);
}
/**
* Write a byte
buffer to the underlying output stream in
* XDR format.
*
* @param buffer The byte
buffer to be written
* @throws IOException if an error occurs while writing to the
* underlying output stream
*/
public void writeBuffer(byte[] buffer) throws IOException {
if (buffer == null)
writeInt(0);
else {
int len = buffer.length;
writeInt(len);
write(buffer, len, (4 - len) & 3);
}
}
/**
* Write a blob buffer to the underlying output stream in XDR format.
*
* @param buffer A byte
array containing the blob
* @throws IOException if an error occurs while writing to the
* underlying output stream
*/
public void writeBlobBuffer(byte[] buffer) throws IOException {
int len = buffer.length ; // 2 for short for buffer length
if (log != null && log.isDebugEnabled()) log.debug("writeBlobBuffer len: " + len);
if (len > Short.MAX_VALUE) {
throw new IOException(""); //Need a value???
}
writeInt(len + 2);
writeInt(len + 2); //bizarre but true! three copies of the length
checkBufferSize(2);
buf[count++] = (byte) ((len >> 0) & 0xff);
buf[count++] = (byte) ((len >> 8) & 0xff);
write(buffer, len, ((4 - len+2)&3));
}
/**
* Write a String
to the underlying output stream in
* XDR format.
*
* @param s The String
to be written
* @throws IOException if an error occurs while writing to the
* underlying output stream
*/
public void writeString(String s) throws IOException {
byte[] buffer = s.getBytes();
writeBuffer(buffer);
/*
int len = buffer.length;
writeInt(len);
if (len > 0) {
write(buffer, len, (4 - len) & 3);
}
*/
}
/**
* Write content of the specified string using the specified Java encoding.
*/
public void writeString(String s, String encoding) throws IOException {
if (encoding != null)
writeBuffer(s.getBytes(encoding));
else
writeBuffer(s.getBytes());
}
/**
* Write a set of distinct byte values (ie parameter buffer).
*
* @param type The type of the parameter value being written,
* e.g. {@link ISCConstants#isc_tpb_version3}
* @param s The set of byte values to be written
* @throws IOException if an error occurs while writing to the
* underlying output stream
*/
public void writeSet(int type, byte[] s) throws IOException {
if (s == null) {
writeInt(1);
checkBufferSize(1);
buf[count++] = (byte) type; //e.g. gds.isc_tpb_version3
}
else {
int len = s.length;
writeInt(len + 1);
checkBufferSize(1);
buf[count++] = (byte) type;
write(s, len, (4 - (len+1)) & 3);
}
}
/**
* Write an Xdrable
to this output stream.
*
* @param type Type of the Xdrable
to be written,
* e.g. {@link ISCConstants#isc_tpb_version3}
* @param item The object to be written
* @throws IOException if an error occurs while writing to the
* underlying output stream
*/
public void writeTyped(int type, Xdrable item) throws IOException {
int size;
if (item == null) {
writeInt(1);
checkBufferSize(1);
buf[count++] = (byte) type; //e.g. gds.isc_tpb_version3
size = 1;
}
else {
size = item.getLength() + 1;
writeInt(size);
checkBufferSize(1);
buf[count++] = (byte) type; //e.g. gds.isc_tpb_version3
item.write(this);
}
count += (4 - size) & 3;
}
//
// WriteSQLData methods
//
/**
* Write a set of SQL data from a XSQLDA
data structure.
*
* @param xsqlda The datastructure containing the SQL data to be written
* @throws IOException if an error occurs while writing to the
* underlying output stream
*/
public void writeSQLData(XSQLDA xsqlda) throws IOException {
for (int i = 0; i < xsqlda.sqld; i++) {
XSQLVAR xsqlvar = xsqlda.sqlvar[i];
if (log != null && log.isDebugEnabled()) {
if (out == null) {
log.debug("db.out null in writeSQLDatum");
}
if (xsqlvar.sqldata == null) {
log.debug("sqldata null in writeSQLDatum: " + xsqlvar);
}
if (xsqlvar.sqldata == null) {
log.debug("sqldata still null in writeSQLDatum: " + xsqlvar);
}
}
int len = xsqlda.ioLength[i];
byte[] buffer = xsqlvar.sqldata;
if (len==0) {
if (buffer != null) {
len = buffer.length;
writeInt(len);
write(buffer, len, (4 - len) & 3);
// sqlind
write(zero, 4, 0);
}
else{
writeInt(0);
// sqlind
write(minusOne, 4, 0);
}
}
else if (len < 0){
if (buffer != null) {
write(buffer, -len, 0);
// sqlind
write(zero,4, 0);
}
else{
write(textPad, -len, 0);
// sqlind
write(minusOne, 4, 0);
}
}
else {
// decrement length because it was incremented before
len--;
if (buffer != null) {
int buflen = buffer.length;
if (buflen >=len){
write(buffer, len, (4 - len) & 3);
}
else{
write(buffer, buflen, 0);
write(textPad, len- buflen, (4 - len) & 3);
}
// sqlind
write(zero, 4, 0);
}
else{
write(textPad, len, (4 - len) & 3);
// sqlind
write(minusOne, 4, 0);
}
}
}
}
//
// DataOutputStream methods
//
/**
* Write a long
value to the underlying stream in XDR format.
*
* @param v The long
value to be written
* @throws IOException if an error occurs while writing to the
* underlying output stream
*/
public void writeLong(long v) throws IOException {
checkBufferSize(8);
buf[count++] = (byte) (v >>> 56 & 0xFF);
buf[count++] = (byte) (v >>> 48 & 0xFF);
buf[count++] = (byte) (v >>> 40 & 0xFF);
buf[count++] = (byte) (v >>> 32 & 0xFF);
buf[count++] = (byte) (v >>> 24 & 0xFF);
buf[count++] = (byte) (v >>> 16 & 0xFF);
buf[count++] = (byte) (v >>> 8 & 0xFF);
buf[count++] = (byte) (v >>> 0 & 0xFF);
}
/**
* Write an int
value to the underlying stream in XDR format.
*
* @param v The int
value to be written
* @throws IOException if an error occurs while writing to the
* underlying output stream
*/
public void writeInt(int v) throws IOException {
checkBufferSize(4);
buf[count++] = (byte) (v >>> 24);
buf[count++] = (byte) (v >>> 16);
buf[count++] = (byte) (v >>> 8);
buf[count++] = (byte) (v >>> 0);
}
//
// Buffering
// If the piece to write is greater than 256 bytes, write it directly
//
/**
* Write a byte
buffer to the underlying output stream
* in XDR format
*
* @param b The byte
buffer to be written
* @param len The number of bytes to write
* @param pad The number of (blank) padding bytes to write
* @throws IOException if an error occurs while writing to the
* underlying output stream
*/
public void write(byte[] b, int len, int pad) throws IOException {
if (len > 256 || count + len >= BUF_SIZE){
if (count > 0)
out.write(buf, 0, count);
out.write(b, 0, len);
out.write(textPad, 0, pad);
count = 0;
}
else {
checkBufferSize(len + pad);
System.arraycopy(b, 0, buf, count, len);
count += len;
System.arraycopy(textPad, 0, buf, count, pad);
count += pad;
}
}
/**
* Write a single byte
to the underlying output stream in
* XDR format.
*
* @param b The value to be written, will be truncated to a byte
* @throws IOException if an error occurs while writing to the
* underlying output stream
*/
public void write(int b) throws IOException {
checkBufferSize(1);
buf[count++] = (byte)b;
}
/**
* Write an array of byte
s to the underlying output stream
* in XDR format.
*
* @param b The byte
array to be written
* @throws IOException if an error occurs while writing to the
* underlying output stream
*/
public void write(byte b[]) throws IOException{
write(b,b.length, 0);
}
/**
* Flush all buffered data to the underlying output stream.
*
* @throws IOException if an error occurs while writing to the
* underlying output stream
*/
public void flush() throws IOException {
if (count > 0){
out.write(buf,0,count);
}
count=0;
out.flush();
}
/**
* Close this stream and the underlying output stream.
*
* @throws IOException if an error occurs while closing the
* underlying stream
*/
public void close() throws IOException {
out.close();
}
/**
* Ensure that there is room in the buffer for a given number
* of direct writes to it.
* @param countToWrite The size of write that is being checked.
* @throws IOException If a write to the underlying OutputStream fails
*/
private void checkBufferSize(int countToWrite) throws IOException {
if (BUF_SIZE - count <= countToWrite){
out.write(buf, 0, count);
count = 0;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy