package org.simantics.databoard.util.binary; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; /** * DataInput and DataOutput serialize primitive numbers with big endian byte * order. This utility absolutely does nothing but facades byte operations. * * @author Toni Kalajainen */ public class Endian { public static void writeUInt24(DataOutput out, int value) throws IOException { out.write((value >> 16) & 0xff); out.write((value >> 8) & 0xff); out.write( value & 0xff); } public static int readUInt24(DataInput in) throws IOException { return ( ( in.readByte() << 16) ) & 0xffffff | ( in.readByte() << 8) | ( in.readByte() ); } /** * Write UInt32 with dynamic encoding (1-5 bytes). * * @param out * @param length * @throws IOException */ public static void writeDynamicUInt32(DataOutput out, int length) throws IOException { if(length < 0x80) { out.write((byte)length); } else { length -= 0x80; if(length < 0x4000) { out.write( ((length&0x3f) | 0x80) ); out.write( (length>>>6) ); } else { length -= 0x4000; if(length < 0x200000) { out.write( ((length&0x1f) | 0xc0) ); out.write( ((length>>>5)&0xff) ); out.write( ((length>>>13)&0xff) ); } else { length -= 0x200000; if(length < 0x10000000) { out.write( ((length&0x0f) | 0xe0) ); out.write( ((length>>>4)&0xff) ); out.write( ((length>>>12)&0xff) ); out.write( ((length>>>20)&0xff) ); } else { length -= 0x10000000; out.write( ((length&0x07) | 0xf0) ); out.write( ((length>>>3)&0xff) ); out.write( ((length>>>11)&0xff) ); out.write( ((length>>>19)&0xff) ); out.write( ((length>>>27)&0xff) ); } } } } } public static int readDynamicUInt32(DataInput in) throws IOException { int length = in.readByte()&0xff; if(length >= 0x80) { if(length >= 0xc0) { if(length >= 0xe0) { if(length >= 0xf0) { length &= 0x0f; length += ((in.readByte()&0xff)<<3); length += ((in.readByte()&0xff)<<11); length += ((in.readByte()&0xff)<<19); length += 0x10204080; } else { length &= 0x1f; length += ((in.readByte()&0xff)<<4); length += ((in.readByte()&0xff)<<12); length += ((in.readByte()&0xff)<<20); length += 0x204080; } } else { length &= 0x3f; length += ((in.readByte()&0xff)<<5); length += ((in.readByte()&0xff)<<13); length += 0x4080; } } else { length &= 0x7f; length += ((in.readByte()&0xff)<<6); length += 0x80; } } return length; } /** * Get number of bytes for dynamic encoding of UInt32 (1-5 bytes) * * @param length length value * @return bytes required (1-5) */ public static int getDynamicUInt32Length(int length) { if(length < 0x80) return 1; if(length < 0x4080) return 2; if(length < 0x204000) return 3; if(length < 0x10200000) return 4; return 5; } /** * Decode an unsigned integer. The number of bytes read depends on maxValue. * * @param in * @param maxValue * @return int * @throws IOException */ public static int getUInt(DataInput in, int maxValue) throws IOException { if (maxValue==0) return 0; if (maxValue<0x100) { return in.readByte() & 0xFF; } else if (maxValue<0x10000) { return in.readShort() & 0xFFFF; } else if (maxValue<0x1000000) { return Endian.readUInt24(in) & 0xFFFFFF; } else { return in.readInt(); } } /** * Calculate unsigned integer encoding length. * * @param maxValue * @return 0-4 bytes */ public static int getUIntLength(int maxValue) { if (maxValue==0) { return 0; } else if (maxValue<0x100) { return 1; } else if (maxValue<0x10000) { return 2; } else if (maxValue<0x1000000) { return 3; } else { return 4; } } /** * Encode and write an unsigned integer. The number of bytes written * depends on the maxValue. * * @param out * @param value * @param maxValue * @throws IOException */ public static void putUInt(DataOutput out, int value, int maxValue) throws IOException { if (maxValue==0) {} else if (maxValue<0x100) { out.write(value); } else if (maxValue<0x10000) { out.writeShort(value); } else if (maxValue<0x1000000) { writeUInt24(out, value); } else { out.writeInt(value); } } }