package org.nustaq.serialization.coders;
import org.nustaq.serialization.FSTClazzInfo;
import org.nustaq.serialization.FSTClazzNameRegistry;
import org.nustaq.serialization.FSTConfiguration;
import org.nustaq.serialization.FSTDecoder;
import org.nustaq.serialization.util.FSTInputStream;
import org.nustaq.serialization.util.FSTUtil;
import java.io.IOException;
import java.io.InputStream;
/**
* decodes a stream written with FTSStreamEnconder
*/
public class FSTStreamDecoder implements FSTDecoder {
private FSTInputStream input;
byte ascStringCache[];
FSTConfiguration conf;
public FSTClazzNameRegistry clnames;
public FSTStreamDecoder(FSTConfiguration conf) {
this.conf = conf;
clnames = (FSTClazzNameRegistry) conf.getCachedObject(FSTClazzNameRegistry.class);
if (clnames == null) {
clnames = new FSTClazzNameRegistry(conf.getClassRegistry(), conf);
} else {
clnames.clear();
}
}
public void ensureReadAhead(int bytes) {
input.ensureReadAhead(bytes);
}
char chBufS[];
char[] getCharBuf(int siz) {
char chars[] = chBufS;
if (chars == null || chars.length < siz) {
chars = new char[Math.max(siz,15)];
chBufS = chars;
}
return chars;
}
public String readStringUTF() throws IOException {
int len = readFInt();
char[] charBuf = getCharBuf(len*3);
input.ensureReadAhead(len * 3);
byte buf[] = input.buf;
int count = input.pos;
int chcount = 0;
for (int i = 0; i < len; i++) {
char head = (char) ((buf[count++] + 256) &0xff);
if (head < 255) {
charBuf[chcount++] = head;
} else {
int ch1 = ((buf[count++] + 256) &0xff);
int ch2 = ((buf[count++] + 256) &0xff);
charBuf[chcount++] = (char) ((ch1 << 0) + (ch2 << 8));
}
}
input.pos = count;
return new String(charBuf, 0, chcount);
}
public byte readObjectHeaderTag() throws IOException {
return readFByte();
}
/**
* len < 127 !!!!!
*
* @return
* @throws java.io.IOException
*/
@Override
public String readStringAsc() throws IOException {
int len = readFInt();
if (ascStringCache == null || ascStringCache.length < len)
ascStringCache = new byte[len];
input.ensureReadAhead(len);
System.arraycopy(input.buf, input.pos, ascStringCache, 0, len);
input.pos += len;
return new String(ascStringCache, 0, 0, len);
}
/**
* assumes class header+len already read
*
* @param componentType
* @param len
* @return
*/
@Override
public Object readFPrimitiveArray(Object array, Class componentType, int len) {
try {
if (componentType == byte.class) {
byte[] arr = (byte[]) array;
ensureReadAhead(arr.length); // fixme: move this stuff to the stream !
System.arraycopy(input.buf,input.pos,arr,0,len);
input.pos += len;
return arr;
} else if (componentType == int.class) {
final int[] arr = (int[]) array;
readFIntArr(len, arr);
return arr;
} else if (componentType == long.class) {
long[] arr = (long[]) array;
readFLongArr(len, arr);
return arr;
} else if (componentType == char.class) {
char[] arr = (char[]) array;
for (int j = 0; j < len; j++) {
arr[j] = readFChar();
}
return arr;
} else if (componentType == double.class) {
double[] arr = (double[]) array;
ensureReadAhead(arr.length * 8);
for (int j = 0; j < len; j++) {
arr[j] = readFDouble();
}
return arr;
} else if (componentType == short.class) {
short[] arr = (short[]) array;
ensureReadAhead(arr.length * 2);
for (int j = 0; j < len; j++) {
arr[j] = readFShort();
}
return arr;
} else if (componentType == float.class) {
float[] arr = (float[]) array;
ensureReadAhead(arr.length * 4);
for (int j = 0; j < len; j++) {
arr[j] = readFFloat();
}
return arr;
} else if (componentType == boolean.class) {
boolean[] arr = (boolean[]) array;
ensureReadAhead(arr.length);
for (int j = 0; j < len; j++) {
arr[j] = readFByte() == 0 ? false : true;
}
return arr;
} else {
throw new RuntimeException("unexpected primitive type " + componentType.getName());
}
} catch (IOException e) {
throw FSTUtil.rethrow(e); //To change body of catch statement use File | Settings | File Templates.
}
}
@Override
public void readFIntArr(int len, int[] arr) throws IOException {
int bytelen = arr.length * 4;
ensureReadAhead(bytelen);
int count = input.pos;
final byte buf[] = input.buf;
for (int j = 0; j < len; j++) {
int ch1 = (buf[count++] + 256) & 0xff;
int ch2 = (buf[count++] + 256) & 0xff;
int ch3 = (buf[count++] + 256) & 0xff;
int ch4 = (buf[count++] + 256) & 0xff;
arr[j] = (ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0);
}
input.pos+=bytelen;
}
public void readFLongArr(int len, long[] arr) throws IOException {
int bytelen = arr.length * 8;
ensureReadAhead(bytelen);
int count = input.pos;
final byte buf[] = input.buf;
for (int j = 0; j < len; j++) {
long ch8 = (buf[count++] + 256) & 0xff;
long ch7 = (buf[count++] + 256) & 0xff;
long ch6 = (buf[count++] + 256) & 0xff;
long ch5 = (buf[count++] + 256) & 0xff;
long ch4 = (buf[count++] + 256) & 0xff;
long ch3 = (buf[count++] + 256) & 0xff;
long ch2 = (buf[count++] + 256) & 0xff;
long ch1 = (buf[count++] + 256) & 0xff;
arr[j] = ((ch1 << 56) + (ch2 << 48) + (ch3 << 40) + (ch4 << 32) + (ch5 << 24) + (ch6 << 16) + (ch7 << 8) + (ch8 << 0));
}
input.pos+=bytelen;
}
@Override
public int readFInt() throws IOException {
ensureReadAhead(5);
final byte head = readFByte();
// -128 = short byte, -127 == 4 byte
if (head > -127 && head <= 127) {
return head;
}
if (head == -128) {
int count = input.pos;
final byte buf[] = input.buf;
int ch1 = (buf[count++] + 256) & 0xff;
int ch2 = (buf[count++] + 256) & 0xff;
input.pos = count;
return (short) ((ch2 << 8) + (ch1 << 0));
} else {
int count = input.pos;
final byte buf[] = input.buf;
int ch1 = (buf[count++] + 256) & 0xff;
int ch2 = (buf[count++] + 256) & 0xff;
int ch3 = (buf[count++] + 256) & 0xff;
int ch4 = (buf[count++] + 256) & 0xff;
input.pos = count;
int res = (ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0);
return res;
}
}
@Override
public double readFDouble() throws IOException {
return Double.longBitsToDouble(readPlainLong());
}
/**
* Reads a 4 byte float.
*/
@Override
public float readFFloat() throws IOException {
return Float.intBitsToFloat(readPlainInt());
}
@Override
public final byte readFByte() throws IOException {
input.ensureReadAhead(1);
return input.buf[input.pos++];
}
@Override
public long readFLong() throws IOException {
input.ensureReadAhead(9);
byte head = readFByte();
// -128 = short byte, -127 == 4 byte
if (head > -126 && head <= 127) {
return head;
}
if (head == -128) {
int count = input.pos;
final byte buf[] = input.buf;
int ch1 = (buf[count++] + 256) & 0xff;
int ch2 = (buf[count++] + 256) & 0xff;
input.pos = count;
return (short) ((ch2 << 8) + (ch1 << 0));
} else if (head == -127) {
int count = input.pos;
final byte buf[] = input.buf;
int ch1 = (buf[count++] + 256) & 0xff;
int ch2 = (buf[count++] + 256) & 0xff;
int ch3 = (buf[count++] + 256) & 0xff;
int ch4 = (buf[count++] + 256) & 0xff;
input.pos = count;
int res = (ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0);
return res;
} else {
ensureReadAhead(8);
int count = input.pos;
final byte buf[] = input.buf;
long ch8 = (buf[count++] + 256) & 0xff;
long ch7 = (buf[count++] + 256) & 0xff;
long ch6 = (buf[count++] + 256) & 0xff;
long ch5 = (buf[count++] + 256) & 0xff;
long ch4 = (buf[count++] + 256) & 0xff;
long ch3 = (buf[count++] + 256) & 0xff;
long ch2 = (buf[count++] + 256) & 0xff;
long ch1 = (buf[count++] + 256) & 0xff;
input.pos = count;
return ((ch1 << 56) + (ch2 << 48) + (ch3 << 40) + (ch4 << 32) + (ch5 << 24) + (ch6 << 16) + (ch7 << 8) + (ch8 << 0));
}
}
@Override
public char readFChar() throws IOException {
input.ensureReadAhead(3);
char head = (char) ((readFByte() + 256) & 0xff);
// -128 = short byte, -127 == 4 byte
if (head >= 0 && head < 255) {
return head;
}
int ch1 = readFByte() & 0xff;
int ch2 = readFByte() & 0xff;
return (char)((ch1 << 0) + (ch2 << 8));
}
@Override
public short readFShort() throws IOException {
input.ensureReadAhead(3);
int head = readFByte() & 0xff;
if (head >= 0 && head < 255) {
return (short) head;
}
int ch1 = readFByte() & 0xff;
int ch2 = readFByte() & 0xff;
return (short)((ch1 << 0) + (ch2 << 8));
}
private char readPlainChar() throws IOException {
input.ensureReadAhead(2);
int count = input.pos;
final byte buf[] = input.buf;
int ch2 = (buf[count++] + 256) & 0xff;
int ch1 = (buf[count++] + 256) & 0xff;
input.pos = count;
return (char) ((ch1 << 8) + (ch2 << 0));
}
private short readPlainShort() throws IOException {
input.ensureReadAhead(2);
int count = input.pos;
final byte buf[] = input.buf;
int ch1 = (buf[count++] + 256) & 0xff;
int ch2 = (buf[count++] + 256) & 0xff;
input.pos = count;
return (short) ((ch2 << 8) + (ch1 << 0));
}
@Override
public int readPlainInt() throws IOException {
input.ensureReadAhead(4);
int count = input.pos;
final byte buf[] = input.buf;
int ch1 = (buf[count++] + 256) & 0xff;
int ch2 = (buf[count++] + 256) & 0xff;
int ch3 = (buf[count++] + 256) & 0xff;
int ch4 = (buf[count++] + 256) & 0xff;
input.pos = count;
int res = (ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0);
return res;
}
private long readPlainLong() throws IOException {
input.ensureReadAhead(8);
int count = input.pos;
final byte buf[] = input.buf;
long ch8 = (buf[count++] + 256) & 0xff;
long ch7 = (buf[count++] + 256) & 0xff;
long ch6 = (buf[count++] + 256) & 0xff;
long ch5 = (buf[count++] + 256) & 0xff;
long ch4 = (buf[count++] + 256) & 0xff;
long ch3 = (buf[count++] + 256) & 0xff;
long ch2 = (buf[count++] + 256) & 0xff;
long ch1 = (buf[count++] + 256) & 0xff;
input.pos = count;
return ((ch1 << 56) + (ch2 << 48) + (ch3 << 40) + (ch4 << 32) + (ch5 << 24) + (ch6 << 16) + (ch7 << 8) + (ch8 << 0));
}
@Override
public byte[] getBuffer() {
return input.buf;
}
@Override
public int getInputPos() {
return input.pos;
}
@Override
public void moveTo(int position) {
input.pos = position;
}
@Override
public void reset() {
input.reset();
clnames.clear();
}
@Override
public void setInputStream(InputStream in) {
if ( input == null )
input = new FSTInputStream(in);
else
input.initFromStream(in);
clnames.clear();
}
@Override
public void resetToCopyOf(byte[] bytes, int off, int len) {
input.reset();
input.ensureCapacity(len);
input.count = len;
System.arraycopy(bytes, off, input.buf, 0, len);
clnames.clear();
}
@Override
public void resetWith(byte[] bytes, int len) {
clnames.clear();
input.reset();
input.count = len;
input.buf = bytes;
input.pos = 0;
}
@Override
public FSTClazzInfo readClass() throws IOException, ClassNotFoundException {
return clnames.decodeClass(this);
}
@Override
public Class classForName(String name) throws ClassNotFoundException {
return clnames.classForName(name);
}
@Override
public void registerClass(Class possible) {
clnames.registerClass(possible);
}
@Override
public void close() {
conf.returnObject(clnames);
}
@Override
public void skip(int n) {
input.pos+=n;
}
@Override
public void readPlainBytes(byte[] b, int off, int len) {
input.ensureReadAhead(len);
System.arraycopy(input.buf,input.pos,b,off,len);
input.pos += len;
}
@Override
public boolean isMapBased() {
return false;
}
@Override
public Object getDirectObject() // in case class already resolves to read object (e.g. mix input)
{
return null;
}
@Override
public int getObjectHeaderLen()
{
return -1;
}
@Override
public void consumeEndMarker() {}
@Override
public Class readArrayHeader() throws Exception {
return readClass().getClazz();
}
@Override
public void readExternalEnd() {
// do nothing for direct encoding
}
@Override
public boolean isEndMarker(String s) {
return false;
}
@Override
public int readVersionTag() throws IOException {
return readFByte();
}
}