/** * */ package net.varkhan.base.conversion.serializer.primitives; import net.varkhan.base.conversion.serializer.DecodingException; import net.varkhan.base.conversion.serializer.EncodingException; import net.varkhan.base.conversion.serializer.Serializer; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.BufferOverflowException; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.ReadOnlyBufferException; /** * <b>Variadic integer serializer</b>. * <p/> * Serializes long integer values as a variable number of bytes. * <p/> * Values between 0 and 127 are serialized as this value, on one byte. * Higher values are serialized on 2 to 10 bytes, by increments of 7 bits * of value size. Negative values are encoded on 10 bytes. * <p/> * All bytes except the final one have their bit sign set to one, * the absence of the bit sign signals the end of the sequence. * <p/> * * @author varkhan * @date Nov 7, 2010 * @time 11:58:15 PM */ public class VariadicSerializer<C> implements Serializer<Long,C> { public Long decode(InputStream stm, C ctx) { return _decode(stm); } public Long decode(ByteBuffer buf, C ctx) { return _decode(buf); } public Long decode(byte[] dat, long pos, long len, C ctx) { return _decode(dat, pos, len); } public long encode(Long obj, OutputStream stm, C ctx) { return _encode(obj, stm); } public long encode(Long obj, ByteBuffer buf, C ctx) { return _encode(obj, buf); } public long encode(Long obj, byte[] dat, long pos, long len, C ctx) { return _encode(obj, dat, pos, len); } public long length(Long obj, C ctx) { return _length(obj); } public static long _decode(InputStream stm) { try { long v=0; int off=0; int r=stm.read(); if(r<0) throw new DecodingException(); byte b=(byte) r; while(off++<9) { if(b>=0) return v|b; v=(v|(-b-1))<<7; r=stm.read(); if(r<0) throw new DecodingException(); b=(byte) r; } return v|b; } catch(IOException e) { throw new DecodingException(e); } } public static long _decode(ByteBuffer buf) { try { long v=0; int off=0; byte b=buf.get(); while(off++<9) { if(b>=0) return v|b; v=(v|(-b-1))<<7; b=buf.get(); } return v|b; } catch(BufferUnderflowException e) { throw new DecodingException(e); } } public static long _decode(byte[] dat, long pos, long len) { try { long v=0; int off=0; byte b=dat[(int) pos++]; while(off++<9) { if(b>=0) return v|b; v=(v|(-b-1))<<7; if(off>len) throw new DecodingException("Buffer underflow at byte "+off); b=dat[(int) pos++]; } return v|b; } catch(ArrayIndexOutOfBoundsException e) { throw new DecodingException(e); } } public static long _encode(long v, OutputStream stm) { try { final int l=(int) _length(v); final byte[] dat=new byte[l]; int off=l-1; dat[(int) off]=(byte) (v&0x7F); while(off-->0) { v>>>=7; dat[off]=(byte) (-(v&0x7F)-1); } stm.write(dat); return l; } catch(IOException e) { throw new EncodingException(e); } } public static long _encode(long v, ByteBuffer buf) { try { final int l=(int) _length(v); final byte[] dat=new byte[l]; int off=l-1; dat[(int) off]=(byte) (v&0x7F); while(off-->0) { v>>>=7; dat[off]=(byte) (-(v&0x7F)-1); } buf.put(dat); return l; } catch(BufferOverflowException e) { throw new EncodingException(e); } catch(ReadOnlyBufferException e) { throw new EncodingException(e); } } public static long _encode(long v, byte[] dat, long pos, long len) { final int l=(int) _length(v); int off=l-1; pos+=off; dat[(int) pos]=(byte) (v&0x7F); while(off-->0) { v>>>=7; dat[(int) --pos]=(byte) (-(v&0x7F)-1); } return l; } public static long _length(long v) { if(v<0) return 10; if(v<(1L<<7)) return 1; if(v<(1L<<14)) return 2; if(v<(1L<<21)) return 3; if(v<(1L<<28)) return 4; if(v<(1L<<35)) return 5; if(v<(1L<<42)) return 6; if(v<(1L<<49)) return 7; if(v<(1L<<56)) return 8; return 9; } }