Files
mongo/lang/java/src/com/wiredtiger/db/PackOutputStream.java

164 lines
5.4 KiB
Java
Raw Normal View History

package com.wiredtiger.db;
import java.io.ByteArrayOutputStream;
import java.lang.StringBuffer;
import com.wiredtiger.db.WiredTigerPackingException;
public class PackOutputStream {
final static int MAX_INT_BYTES = 21;
protected PackFormatInputStream format;
protected ByteArrayOutputStream packed;
protected byte[] intBuf;
public PackOutputStream(String format) {
this.format = new PackFormatInputStream(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 reset() {
format.reset();
packed.reset();
}
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);
}
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);
// If this is not the last item, store the size.
if (format.available() > 0)
packLong(len, false);
packed.write(value, off, len);
/* TODO: padding. */
}
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);
}
//
// Strings have two possible encodings. A lower case 's' is not null
// terminated, and has a length define in the format (default 1). An
// upper case 'S' is variable length and has a null terminator.
public void addFieldString(String value)
throws WiredTigerPackingException {
format.checkFieldType('s', false);
char fieldFormat = format.getFieldType();
int stringLen = 0;
int padBytes = 0;
if (fieldFormat == 's') {
stringLen = format.getLengthFromFormat(true);
if (stringLen > value.length())
padBytes = stringLen - value.length();
} else {
stringLen = value.length();
padBytes = 1; // Null terminator
}
// We're done pulling information from the field now.
format.consumeField();
// Use the default Charset.
packed.write(value.getBytes(), 0, stringLen);
while(padBytes-- > 0)
packed.write(0);
}
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);
}
}