164 lines
5.4 KiB
Java
164 lines
5.4 KiB
Java
|
|
package com.wiredtiger.db;
|
||
|
|
|
||
|
|
import java.io.ByteArrayOutputStream;
|
||
|
|
import java.lang.StringBuffer;
|
||
|
|
import com.wiredtiger.db.WiredTigerPackingException;
|
||
|
|
|
||
|
|
public class PackInputStream {
|
||
|
|
|
||
|
|
final static int MAX_INT_BYTES = 21;
|
||
|
|
protected PackFormatOutputStream format;
|
||
|
|
protected ByteArrayOutputStream packed;
|
||
|
|
protected byte[] intBuf;
|
||
|
|
|
||
|
|
public PackInputStream(String format) {
|
||
|
|
this.format = new PackFormatOutputStream(format);
|
||
|
|
intBuf = new byte[MAX_INT_BYTES];
|
||
|
|
packed = new ByteArrayOutputStream(100);
|
||
|
|
}
|
||
|
|
|
||
|
|
public String getFormat() {
|
||
|
|
return format.toString();
|
||
|
|
}
|
||
|
|
|
||
|
|
public byte[] getValue() {
|
||
|
|
return packed.toByteArray();
|
||
|
|
}
|
||
|
|
|
||
|
|
public void addFieldByte(byte value)
|
||
|
|
throws WiredTigerPackingException {
|
||
|
|
format.checkFieldType('b', true);
|
||
|
|
/* Translate to maintain ordering with the sign bit. */
|
||
|
|
byte input = (byte)(value + 0x80);
|
||
|
|
packed.write(input);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Adds a byte array as part of a complex format (which stores the size in
|
||
|
|
* the encoding).
|
||
|
|
* Format strings that consist solely of a byte array should use the
|
||
|
|
* addFieldByteArrayRaw method.
|
||
|
|
*/
|
||
|
|
public void addFieldByteArray(byte[] value)
|
||
|
|
throws WiredTigerPackingException {
|
||
|
|
this.addFieldByteArray(value, 0, value.length);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void addFieldByteArray(byte[] value, int off, int len)
|
||
|
|
throws WiredTigerPackingException {
|
||
|
|
format.checkFieldType('U', true);
|
||
|
|
packLong(len, false);
|
||
|
|
packed.write(value, off, len);
|
||
|
|
/* TODO: padding. */
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Adds a byte array as the only part of a packed format (which does not
|
||
|
|
* store the size in the encoding).
|
||
|
|
*/
|
||
|
|
public void addFieldByteArrayRaw(byte[] value)
|
||
|
|
throws WiredTigerPackingException {
|
||
|
|
this.addFieldByteArrayRaw(value, 0, value.length);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void addFieldByteArrayRaw(byte[] value, int off, int len)
|
||
|
|
throws WiredTigerPackingException {
|
||
|
|
format.checkFieldType('u', true);
|
||
|
|
/* TODO: padding. */
|
||
|
|
packed.write(value, off, len);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void addFieldInt(int value)
|
||
|
|
throws WiredTigerPackingException {
|
||
|
|
format.checkFieldType('i', true);
|
||
|
|
packLong(value, true);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void addFieldLong(long value)
|
||
|
|
throws WiredTigerPackingException {
|
||
|
|
format.checkFieldType('q', true);
|
||
|
|
packLong(value, true);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void addFieldRecord(long value)
|
||
|
|
throws WiredTigerPackingException {
|
||
|
|
format.checkFieldType('r', true);
|
||
|
|
packLong(value, true);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void addFieldShort(short value)
|
||
|
|
throws WiredTigerPackingException {
|
||
|
|
format.checkFieldType('h', true);
|
||
|
|
packLong(value, true);
|
||
|
|
}
|
||
|
|
|
||
|
|
public void addFieldString(String value)
|
||
|
|
throws WiredTigerPackingException {
|
||
|
|
format.checkFieldType('S', true);
|
||
|
|
/* Use the default Charset. */
|
||
|
|
try {
|
||
|
|
packed.write(value.getBytes());
|
||
|
|
} catch(java.io.IOException ioe) {
|
||
|
|
throw new WiredTigerPackingException(
|
||
|
|
"Error retrieving content from string.");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void packLong(long x, boolean signed)
|
||
|
|
throws WiredTigerPackingException {
|
||
|
|
int offset = 0;
|
||
|
|
|
||
|
|
if (!signed && x < 0)
|
||
|
|
throw new WiredTigerPackingException("Overflow packing long.");
|
||
|
|
|
||
|
|
if (x < PackUtil.NEG_2BYTE_MIN) {
|
||
|
|
intBuf[offset] = PackUtil.NEG_MULTI_MARKER;
|
||
|
|
int lz = Long.numberOfLeadingZeros(~x) / 8;
|
||
|
|
int len = PackUtil.SIZEOF_LONG - lz;
|
||
|
|
|
||
|
|
/*
|
||
|
|
* There are four size bits we can use in the first
|
||
|
|
* byte. For negative numbers, we store the number of
|
||
|
|
* leading 0xff byes to maintain ordering (if this is
|
||
|
|
* not obvious, it may help to remember that -1 is the
|
||
|
|
* largest negative number).
|
||
|
|
*/
|
||
|
|
intBuf[offset++] |= (lz & 0xf);
|
||
|
|
|
||
|
|
for (int shift = (len - 1) << 3;
|
||
|
|
len != 0; shift -= 8, --len)
|
||
|
|
intBuf[offset++] = (byte)(x >> shift);
|
||
|
|
} else if (x < PackUtil.NEG_1BYTE_MIN) {
|
||
|
|
x -= PackUtil.NEG_2BYTE_MIN;
|
||
|
|
intBuf[offset++] =
|
||
|
|
(byte)(PackUtil.NEG_2BYTE_MARKER | PackUtil.GET_BITS(x, 13, 8));
|
||
|
|
intBuf[offset++] = PackUtil.GET_BITS(x, 8, 0);
|
||
|
|
} else if (x < 0) {
|
||
|
|
x -= PackUtil.NEG_1BYTE_MIN;
|
||
|
|
intBuf[offset++] =
|
||
|
|
(byte)(PackUtil.NEG_1BYTE_MARKER | PackUtil.GET_BITS(x, 6, 0));
|
||
|
|
} else if (x <= PackUtil.POS_1BYTE_MAX) {
|
||
|
|
intBuf[offset++] =
|
||
|
|
(byte)(PackUtil.POS_1BYTE_MARKER | PackUtil.GET_BITS(x, 6, 0));
|
||
|
|
} else if (x <= PackUtil.POS_2BYTE_MAX) {
|
||
|
|
x -= PackUtil.POS_1BYTE_MAX + 1;
|
||
|
|
intBuf[offset++] =
|
||
|
|
(byte)(PackUtil.POS_2BYTE_MARKER | PackUtil.GET_BITS(x, 13, 8));
|
||
|
|
intBuf[offset++] = PackUtil.GET_BITS(x, 8, 0);
|
||
|
|
} else {
|
||
|
|
x -= PackUtil.POS_2BYTE_MAX + 1;
|
||
|
|
intBuf[offset] = PackUtil.POS_MULTI_MARKER;
|
||
|
|
int lz = Long.numberOfLeadingZeros(x) / 8;
|
||
|
|
int len = PackUtil.SIZEOF_LONG - lz;
|
||
|
|
|
||
|
|
/* There are four bits we can use in the first byte. */
|
||
|
|
intBuf[offset++] |= (len & 0xf);
|
||
|
|
|
||
|
|
for (int shift = (len - 1) << 3;
|
||
|
|
len != 0; --len, shift -= 8)
|
||
|
|
intBuf[offset++] = (byte)(x >> shift);
|
||
|
|
}
|
||
|
|
packed.write(intBuf, 0, offset);
|
||
|
|
}
|
||
|
|
}
|