/* * Copyright 2014 Ruediger Moeller. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.nustaq.serialization.minbin; /** * Date: 12.04.2014 * Time: 22:10 * * Input reader for minbin byte[] */ public class MBIn { MinBin mb; protected byte bytez[]; protected int pos; int count; // length of data public MBIn(byte[] bytez, int pos) { this(MinBin.DefaultInstance,bytez,pos); } public MBIn(MinBin mb, byte[] bytez, int pos) { this.bytez = bytez; this.pos = pos; this.mb = mb; if ( bytez != null ) this.count = bytez.length; } public byte readIn() { if ( pos >= bytez.length ) { return MinBin.END; } return bytez[pos++]; } public byte peekIn() { if ( pos >= bytez.length ) { return MinBin.END; } return bytez[pos]; } private long readRawInt(byte type) { long res = 0; int numBytes = MinBin.extractNumBytes(type); int shift = 0; for ( int i = 0; i < numBytes; i++ ) { long b = (readIn()+256) & 0xff; res += b<<shift; shift+=8; } return res; } public long readInt() { byte type = readIn(); if ( !MinBin.isPrimitive(type) || MinBin.isArray(type)) { pos--; throw new RuntimeException("no integer based id avaiable:"+type); } int numBytes = MinBin.extractNumBytes(type); long l = readRawInt(type); if ( MinBin.isSigned(type) ) { switch (numBytes) { case 1: return (long) (byte) l; case 2: return (long) (short) l; case 4: return (long) (int) l; case 8: return l; default: throw new RuntimeException("Wat?"); } } return l; } public Object readArray() { byte type = readIn(); if ( ! MinBin.isArray(type) || ! MinBin.isPrimitive(type) ) throw new RuntimeException("not a primitive array "+type); int len = (int) readInt(); byte baseType = MinBin.getBaseType(type); Object result; switch (baseType) { case MinBin.INT_8: result = new byte[len]; break; case MinBin.INT_16: result = new short[len]; break; case MinBin.CHAR: result = new char[len]; break; case MinBin.INT_32: result = new int[len]; break; case MinBin.INT_64: result = new long[len]; break; default: throw new RuntimeException("unknown array type"); } return readArrayRaw(type, len, result); } /** * read into preallocated array, allows to write to different type (e.g. boolean[] from byte[]) * @param type type tag. * @param len * @param resultingArray * @return */ public Object readArrayRaw(byte type, int len, Object resultingArray) { Class componentType = resultingArray.getClass().getComponentType(); if ( componentType == byte.class ) { byte[] barr = (byte[]) resultingArray; for ( int i = 0; i < len; i++ ) { barr[i] = (byte) readRawInt(type); } } else if ( componentType == short.class ) { short[] sArr = (short[]) resultingArray; for ( int i = 0; i < len; i++ ) { sArr[i] = (short) readRawInt(type); } } else if ( componentType == char.class ) { char[] cArr = (char[]) resultingArray; for (int i = 0; i < len; i++) { cArr[i] = (char) readRawInt(type); } } else if ( componentType == int.class ) { int[] iArr = (int[]) resultingArray; for (int i = 0; i < len; i++) { iArr[i] = (int) readRawInt(type); } } else if ( componentType == long.class ) { long[] lArr = (long[]) resultingArray; for (int i = 0; i < len; i++) { lArr[i] = readRawInt(type); } } else if ( componentType == boolean.class ) { boolean[] boolArr = (boolean[]) resultingArray; for (int i = 0; i < len; i++) { boolArr[i] = readRawInt(MinBin.INT_8) != 0; } } else throw new RuntimeException("unsupported array type "+resultingArray.getClass().getName()); return resultingArray; } public Object readTag( byte tag ) { int tagId = MinBin.getTagId(tag); MinBin.TagSerializer ts = mb.getSerializerForId(tagId); return ts.readTag(this); } public Object readObject() { byte type = peekIn(); if (type==MinBin.END) { readIn(); return MinBin.END_MARKER; } if ( MinBin.isPrimitive(type) ) { if ( MinBin.isArray(type) ) { return readArray(); } switch (type) { case MinBin.INT_8: return (byte)readInt(); case MinBin.INT_16: return (short)readInt(); case MinBin.CHAR: return (char)readInt(); case MinBin.INT_32: return (int)readInt(); case MinBin.INT_64: return (long)readInt(); default: throw new RuntimeException("unexpected primitive type:"+type); } } else { if ( MinBin.getTagId(type) == MinBin.HANDLE ) { return new MBRef((Integer) readTag(readIn())); } return readTag(readIn()); } } public byte[] getBuffer() { return bytez; } public int getPos() { return pos; } public void setPos(int newpos) { pos = newpos; } public void setBuffer(byte[] buf, int count) { this.bytez = buf; pos = 0; this.count = count; } public void reset() { setBuffer(bytez,count); } public int getCount() { return count; } }