org.firebirdsql.gds.impl.wire.XdrInputStream Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jaybird-jdk17 Show documentation
Show all versions of jaybird-jdk17 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.EOFException;
import java.io.IOException;
import java.io.InputStream;
/**
* XdrInputStream
is an input stream for reading in data that
* is in the XDR format. An XdrInputStream
instance is wrapped
* around an underlying java.io.InputStream
.
*
* @author Alejandro Alberola
* @author David Jencks
* @version 1.0
*/
public class XdrInputStream {
protected final static byte[] pad = new byte[8];
protected InputStream in = null;
// Buffer
protected static int defaultBufferSize = 16384;
protected byte buf[];
protected int count;
protected int pos;
protected XdrInputStream() {
// empty, for subclasses only
}
/**
* Create a new instance of XdrInputStream
.
*
* @param in The underlying InputStream
to read from
*/
public XdrInputStream(InputStream in) {
buf = new byte[defaultBufferSize];
this.in = in;
}
/**
* Read in a byte buffer.
*
* @return The buffer that was read
* @throws IOException if an error occurs while reading from the
* underlying input stream
*/
public byte[] readBuffer() throws IOException {
int len = readInt();
byte[] buffer = new byte[len];
readFully(buffer,0,len);
readFully(pad,0,(4 - len) & 3);
return buffer;
}
/**
* Read in a raw array of bytes.
*
* @param len The number of bytes to read
* @return The byte buffer that was read
* @throws IOException if an error occurs while reading from the
* underlying input stream
*/
public byte [] readRawBuffer(int len) throws IOException {
byte [] buffer = new byte[len];
readFully(buffer, 0, len);
return buffer;
}
/**
* Read in a String
.
*
* @return The String
that was read
* @throws IOException if an error occurs while reading from the
* underlying input stream
*/
public String readString() throws IOException {
int len = readInt();
byte[] buffer = new byte[len];
readFully(buffer,0,len);
readFully(pad,0,(4 - len) & 3);
return new String(buffer);
}
//
// Read SQL data
//
//Now returns results in Object[] and in xsqlda.data
//Nulls are represented by null values in Object array
/**
* Read a row of SQL data and store it in the results set of a statement.
*
* @param ioLength array containing the lengths of each column in the
* data row that is to be read
* @param stmt The statement where the row is to be stored
* @throws IOException if an error occurs while reading from the
* underlying input stream
*/
public void readSQLData(int[] ioLength, isc_stmt_handle_impl stmt) throws IOException {
// This only works if not (port->port_flags & PORT_symmetric)
int numCols = ioLength.length;
byte[][] row = new byte[numCols][];
byte[] buffer;
for (int i = 0; i < numCols; i++) {
int len = ioLength[i];
if (len == 0){
len = readInt();
buffer = new byte[len];
readFully(buffer,0,len);
readFully(pad,0,(4 - len) & 3);
}
else if (len < 0){
buffer = new byte[-len];
readFully(buffer,0,-len);
}
else {
// len is incremented to avoid value 0 so it must be decremented
len --;
buffer = new byte[len];
readFully(buffer,0,len);
readFully(pad,0,(4 - len) & 3);
}
if (readInt()==-1)
buffer = null;
row[i] = buffer;
}
if (stmt != null)
stmt.addRow(row);
}
//
// Substitute DataInputStream
//
/**
* Read in a long
.
*
* @return The long
that was read
* @throws IOException if an error occurs while reading from the
* underlying input stream
*/
public long readLong() throws IOException {
return ((long)read() << 56) | ((long)read() << 48) | ((long)read() << 40) | ((long)read() << 32)
| ((long)read() << 24) | ((long)read() << 16) | ((long)read() << 8) | ((long)read() << 0);
}
/**
* Read in an int
.
*
* @return The int
that was read
* @throws IOException if an error occurs while reading from the
* underlying input stream
*/
public int readInt() throws IOException {
return (read() << 24) | (read() << 16) | (read() << 8) | (read() << 0);
}
/**
* Read in a short
.
*
* @return The short
that was read
* @throws IOException if an error occurs while reading from the
* underlying input stream
*/
public int readShort() throws IOException {
return (read() << 8) | (read() << 0);
}
/**
* Read a given amount of data from the underlying input stream. The data
* that is read is stored in b
, starting from offset
* off
.
*
* @param b The byte buffer to hold the data that is read
* @param off The offset at which to start storing data in b
* @param len The number of bytes to be read
* @throws IOException if an error occurs while reading from the
* underlying input stream
*/
public void readFully(byte b[], int off, int len) throws IOException {
if (len <= count-pos){
System.arraycopy(buf, pos, b, off, len);
pos += len;
}
else {
int n = 0;
while (n < len) {
if (count <= pos){
pos = count = 0;
int readn = in.read(buf, 0, defaultBufferSize);
if (readn > 0)
count = readn;
else
throw new EOFException();
}
int lenN = len-n;
int avail = count - pos;
int cnt = (avail < lenN) ? avail : lenN;
System.arraycopy(buf, pos, b, off+n, cnt);
pos += cnt;
n += cnt;
}
}
}
//
// Buffering classes (those interface with the real InputStream
//
/**
* Read in the next byte of data from the underlying input stream.
*
* @return The value that was read
* @throws IOException if an error occurs while reading from the
* underlying input stream
*/
public int read() throws IOException {
if (pos >= count){
pos = count = 0;
int readn = in.read(buf, 0, defaultBufferSize);
if (readn > 0)
count = readn;
else
throw new EOFException();
}
return buf[pos++] & 0xff;
}
/**
* Close this input stream and the underlying input stream.
*
* @throws IOException if an error occurs while closing the underlying
* input stream
*/
public void close() throws IOException {
if (in == null)
return;
try {
in.close();
} finally {
in = null;
buf = null;
}
}
}