package com.sleepycat.bind.tuple;
import com.sleepycat.util.FastOutputStream;
import com.sleepycat.util.UtfOps;
import de.ovgu.cide.jakutil.*;
/**
* An <code>OutputStream</code> with <code>DataOutput</code>-like methods
* for writing tuple fields. It is used by <code>TupleBinding</code>.
* <p>
* This class has many methods that have the same signatures as methods in the{@link java.io.DataOutput} interface. The reason this class does not
* implement {@link java.io.DataOutput} is because it would break the interface
* contract for those methods because of data format differences.
* </p>
* <p>
* Signed numbers are stored in the buffer in MSB (most significant byte first)
* order with their sign bit (high-order bit) inverted to cause negative numbers
* to be sorted first when comparing values as unsigned byte arrays, as done in
* a database. Unsigned numbers, including characters, are stored in MSB order
* with no change to their sign bit.
* </p>
* <p>
* Strings and character arrays are stored either as a fixed length array of
* unicode characters, where the length must be known by the application, or as
* a null-terminated UTF byte array.
* </p>
* <ul>
* <li>Null strings are UTF encoded as { 0xFF }, which is not allowed in a
* standard UTF encoding. This allows null strings, as distinct from empty or
* zero length strings, to be represented in a tuple. Using the default
* comparator, null strings will be ordered last.</li>
* <li>Zero (0x0000) character values are UTF encoded as non-zero values, and
* therefore embedded zeros in the string are supported. The sequence { 0xC0,
* 0x80 } is used to encode a zero character. This UTF encoding is the same one
* used by native Java UTF libraries. However, this encoding of zero does impact
* the lexicographical ordering, and zeros will not be sorted first (the natural
* order) or last. For all character values other than zero, the default UTF
* byte ordering is the same as the Unicode lexicographical character ordering.</li>
* </ul>
* <p>
* Floats and doubles are stored in standard Java integer-bit representation
* (IEEE 754). Non-negative numbers are correctly ordered by numeric value.
* However, negative numbers are not correctly ordered; therefore, if you use
* negative floating point numbers in a key, you'll need to implement and
* configure a custom comparator to get correct numeric ordering.
* </p>
* @author Mark Hayes
*/
public class TupleOutput extends FastOutputStream {
/**
* We represent a null string as a single FF UTF character, which cannot
* occur in a UTF encoded string.
*/
static final int NULL_STRING_UTF_VALUE=((byte)0xFF);
/**
* Creates a tuple output object for writing a byte array of tuple data.
*/
public TupleOutput(){
super();
}
/**
* Creates a tuple output object for writing a byte array of tuple data,
* using a given buffer. A new buffer will be allocated only if the number
* of bytes needed is greater than the length of this buffer. A reference to
* the byte array will be kept by this object and therefore the byte array
* should not be modified while this object is in use.
* @param bufferis the byte array to use as the buffer.
*/
public TupleOutput( byte[] buffer){
super(buffer);
}
/**
* Writes the specified bytes to the buffer, converting each character to an
* unsigned byte value. Writes values that can be read using{@link TupleInput#readBytes}. Only characters with values below 0x100
* may be written using this method, since the high-order 8 bits of all
* characters are discarded.
* @param valis the string containing the values to be written.
* @return this tuple output object.
* @throws NullPointerExceptionif the val parameter is null.
*/
public final TupleOutput writeBytes( String val){
writeBytes(val.toCharArray());
return this;
}
/**
* Writes the specified characters to the buffer, converting each character
* to a two byte unsigned value. Writes values that can be read using{@link TupleInput#readChars}.
* @param valis the string containing the characters to be written.
* @return this tuple output object.
* @throws NullPointerExceptionif the val parameter is null.
*/
public final TupleOutput writeChars( String val){
writeChars(val.toCharArray());
return this;
}
/**
* Writes the specified characters to the buffer, converting each character
* to UTF format, and adding a null terminator byte. Note that zero (0x0000)
* character values are encoded as non-zero values and a null String
* parameter is encoded as 0xFF. Writes values that can be read using{@link TupleInput#readString()}.
* @param valis the string containing the characters to be written.
* @return this tuple output object.
*/
public final TupleOutput writeString( String val){
if (val != null) {
writeString(val.toCharArray());
}
else {
writeFast(NULL_STRING_UTF_VALUE);
}
writeFast(0);
return this;
}
/**
* Writes a char (two byte) unsigned value to the buffer. Writes values that
* can be read using {@link TupleInput#readChar}.
* @param valis the value to write to the buffer.
* @return this tuple output object.
*/
public final TupleOutput writeChar( int val){
writeFast((byte)(val >>> 8));
writeFast((byte)val);
return this;
}
/**
* Writes a boolean (one byte) unsigned value to the buffer, writing one if
* the value is true and zero if it is false. Writes values that can be read
* using {@link TupleInput#readBoolean}.
* @param valis the value to write to the buffer.
* @return this tuple output object.
*/
public final TupleOutput writeBoolean( boolean val){
writeFast(val ? (byte)1 : (byte)0);
return this;
}
/**
* Writes an signed byte (one byte) value to the buffer. Writes values that
* can be read using {@link TupleInput#readByte}.
* @param valis the value to write to the buffer.
* @return this tuple output object.
*/
public final TupleOutput writeByte( int val){
writeUnsignedByte(val ^ 0x80);
return this;
}
/**
* Writes an signed short (two byte) value to the buffer. Writes values that
* can be read using {@link TupleInput#readShort}.
* @param valis the value to write to the buffer.
* @return this tuple output object.
*/
public final TupleOutput writeShort( int val){
writeUnsignedShort(val ^ 0x8000);
return this;
}
/**
* Writes an signed int (four byte) value to the buffer. Writes values that
* can be read using {@link TupleInput#readInt}.
* @param valis the value to write to the buffer.
* @return this tuple output object.
*/
public final TupleOutput writeInt( int val){
writeUnsignedInt(val ^ 0x80000000);
return this;
}
/**
* Writes an signed long (eight byte) value to the buffer. Writes values
* that can be read using {@link TupleInput#readLong}.
* @param valis the value to write to the buffer.
* @return this tuple output object.
*/
public final TupleOutput writeLong( long val){
writeUnsignedLong(val ^ 0x8000000000000000L);
return this;
}
/**
* Writes an signed float (four byte) value to the buffer. Writes values
* that can be read using {@link TupleInput#readFloat}.
* <code>Float.floatToIntBits</code> is used to convert the signed float
* value.
* @param valis the value to write to the buffer.
* @return this tuple output object.
*/
public final TupleOutput writeFloat( float val){
writeUnsignedInt(Float.floatToIntBits(val));
return this;
}
/**
* Writes an signed double (eight byte) value to the buffer. Writes values
* that can be read using {@link TupleInput#readDouble}.
* <code>Double.doubleToLongBits</code> is used to convert the signed
* double value.
* @param valis the value to write to the buffer.
* @return this tuple output object.
*/
public final TupleOutput writeDouble( double val){
writeUnsignedLong(Double.doubleToLongBits(val));
return this;
}
/**
* Writes the specified bytes to the buffer, converting each character to an
* unsigned byte value. Writes values that can be read using{@link TupleInput#readBytes}. Only characters with values below 0x100
* may be written using this method, since the high-order 8 bits of all
* characters are discarded.
* @param charsis the array of values to be written.
* @return this tuple output object.
* @throws NullPointerExceptionif the chars parameter is null.
*/
public final TupleOutput writeBytes( char[] chars){
for (int i=0; i < chars.length; i++) {
writeFast((byte)chars[i]);
}
return this;
}
/**
* Writes the specified characters to the buffer, converting each character
* to a two byte unsigned value. Writes values that can be read using{@link TupleInput#readChars}.
* @param charsis the array of characters to be written.
* @return this tuple output object.
* @throws NullPointerExceptionif the chars parameter is null.
*/
public final TupleOutput writeChars( char[] chars){
for (int i=0; i < chars.length; i++) {
writeFast((byte)(chars[i] >>> 8));
writeFast((byte)chars[i]);
}
return this;
}
/**
* Writes the specified characters to the buffer, converting each character
* to UTF format. Note that zero (0x0000) character values are encoded as
* non-zero values. Writes values that can be read using{@link TupleInput#readString(int)} or{@link TupleInput#readString(char[])}.
* @param charsis the array of characters to be written.
* @return this tuple output object.
* @throws NullPointerExceptionif the chars parameter is null.
*/
public final TupleOutput writeString( char[] chars){
if (chars.length == 0) return this;
int utfLength=UtfOps.getByteLength(chars);
makeSpace(utfLength);
UtfOps.charsToBytes(chars,0,getBufferBytes(),getBufferLength(),chars.length);
addSize(utfLength);
return this;
}
/**
* Writes an unsigned byte (one byte) value to the buffer. Writes values
* that can be read using {@link TupleInput#readUnsignedByte}.
* @param valis the value to write to the buffer.
* @return this tuple output object.
*/
public final TupleOutput writeUnsignedByte( int val){
writeFast(val);
return this;
}
/**
* Writes an unsigned short (two byte) value to the buffer. Writes values
* that can be read using {@link TupleInput#readUnsignedShort}.
* @param valis the value to write to the buffer.
* @return this tuple output object.
*/
public final TupleOutput writeUnsignedShort( int val){
writeFast((byte)(val >>> 8));
writeFast((byte)val);
return this;
}
/**
* Writes an unsigned int (four byte) value to the buffer. Writes values
* that can be read using {@link TupleInput#readUnsignedInt}.
* @param valis the value to write to the buffer.
* @return this tuple output object.
*/
public final TupleOutput writeUnsignedInt( long val){
writeFast((byte)(val >>> 24));
writeFast((byte)(val >>> 16));
writeFast((byte)(val >>> 8));
writeFast((byte)val);
return this;
}
/**
* This method is private since an unsigned long cannot be treated as such
* in Java, nor converted to a BigInteger of the same value.
*/
private final TupleOutput writeUnsignedLong( long val){
writeFast((byte)(val >>> 56));
writeFast((byte)(val >>> 48));
writeFast((byte)(val >>> 40));
writeFast((byte)(val >>> 32));
writeFast((byte)(val >>> 24));
writeFast((byte)(val >>> 16));
writeFast((byte)(val >>> 8));
writeFast((byte)val);
return this;
}
}