/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.eas.proto.dom;
import com.eas.proto.ProtoReaderException;
import com.eas.proto.ProtoUtil;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author pk
*/
class ProtoLeafNode implements ProtoNode {
private final int nodeTag;
private final byte[] data;
private final int offset;
private final int size;
ProtoLeafNode(int tag, byte[] data, int dataOffset, int size) {
if (data.length < dataOffset + size) {
throw new IllegalArgumentException("Buffer overflow");
}
this.nodeTag = tag;
this.data = data;
this.offset = dataOffset;
this.size = size;
}
@Override
public int getNodeTag() {
return nodeTag;
}
@Override
public byte getByte() throws ProtoReaderException {
if (size == 1) {
return data[offset];
} else {
throw new ProtoReaderException("Wrong size " + size + ", expected 1");
}
}
@Override
public boolean getBoolean() throws ProtoReaderException {
if (size == 1) {
return data[offset] == 1;
} else {
throw new ProtoReaderException("Wrong size " + size + ", expected 1");
}
}
@Override
public Date getDate() throws ProtoReaderException {
return new Date(getLong());
}
@Override
public double getDouble() throws ProtoReaderException {
return Double.longBitsToDouble(getLong());
}
@Override
public float getFloat() throws ProtoReaderException {
return Float.intBitsToFloat(getInt());
}
@Override
public long getEntityID() throws ProtoReaderException {
return getLong();
}
public short getShort() throws ProtoReaderException {
if (size == 2) {
return (short) (((data[offset + 0] & 0xff) << 8) + (data[offset + 1] & 0xff));
} else {
throw new ProtoReaderException("Wrong size " + size + ", expected 2");
}
}
@Override
public int getInt() throws ProtoReaderException {
if (size == 4) {
return (((data[offset + 0] & 0xff) << 24) + ((data[offset + 1] & 0xff) << 16) + ((data[offset + 2] & 0xff) << 8) + ((data[offset + 3] & 0xff)));
} else {
throw new ProtoReaderException("Wrong size " + size + ", expected 4");
}
}
@Override
public long getLong() throws ProtoReaderException {
if (size == 8) {
return (((long) (data[offset + 0] & 0xff) << 56)
+ ((long) (data[offset + 1] & 0xff) << 48)
+ ((long) (data[offset + 2] & 0xff) << 40)
+ ((long) (data[offset + 3] & 0xff) << 32)
+ ((long) (data[offset + 4] & 0xff) << 24)
+ ((data[offset + 5] & 0xff) << 16)
+ ((data[offset + 6] & 0xff) << 8)
+ ((data[offset + 7] & 0xff)));
} else {
throw new ProtoReaderException("Wrong size " + size + ", expected 8");
}
}
@Override
public String getString() {
try {
// This constrcutor is chosen because it doesn't copy input byte array and
// starts to decode it into string immidiatly. So, performance of decoding is pretty and nice.
// If anybody has dicovered the reason of unnessasary copy made by
// folowing constructor: new String(byte[] adata, int offset, int size, Charset aCharset),
// talk to mg bout this!
String val = new String(data, offset, size, ProtoUtil.CHARSET_4_STRING_SERIALIZATION_NAME);
return val;
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(ProtoLeafNode.class.getName()).log(Level.SEVERE, null, ex);
return "";
}
}
@Override
public BigDecimal getBigDecimal() {
byte[] unscaled = new byte[size - Integer.SIZE / Byte.SIZE];
System.arraycopy(data, offset, unscaled, 0, unscaled.length);
int scaleVal = (((data[offset + unscaled.length + 0] & 0xff) << 24) + ((data[offset + unscaled.length + 1] & 0xff) << 16) + ((data[offset + unscaled.length + 2] & 0xff) << 8) + ((data[offset + unscaled.length + 3] & 0xff)));
BigInteger unscaledVal = new BigInteger(unscaled);
BigDecimal val = new BigDecimal(unscaledVal, scaleVal);
return val;
}
@Override
public ProtoNode getChild(int tag) {
throw new UnsupportedOperationException("Unsupported for a leaf node");
}
@Override
public List<ProtoNode> getChildren(int tag) {
throw new UnsupportedOperationException("Unsupported for entity ref node");
}
@Override
public Iterator<ProtoNode> iterator() {
throw new UnsupportedOperationException("Unsupported for a leaf node");
}
@Override
public boolean containsChild(int tag) {
throw new UnsupportedOperationException("Unsupported for a leaf node");
}
@Override
public ProtoNodeType getNodeType() {
return ProtoNodeType.LEAF;
}
public int getOffset() {
return offset;
}
public int getSize() {
return size;
}
public byte[] getData() {
return data;
}
}