package dslog; import java.math.BigInteger; import java.io.InputStream; import java.io.IOException; import java.io.EOFException; import java.time.Instant; class Read { public static void full(InputStream in, byte b[]) throws IOException { int n = 0; while (n < b.length) { int count = in.read(b, n, b.length - n); if (count < 0) throw new EOFException(); n += count; } } public static short u8(InputStream in) throws IOException { int n = in.read(); if (n < 0) throw new EOFException(); return (short)n; } public static byte i8(InputStream in) throws IOException { return (byte)u8(in); } public static int u16(InputStream in) throws IOException { byte bytes[] = new byte[2]; full(in, bytes); return (((bytes[0] & 0xff) << 8) + ((bytes[1] & 0xff) << 0)); } public static short i16(InputStream in) throws IOException { return (short)u16(in); } public static int i32(InputStream in) throws IOException { byte bytes[] = new byte[4]; full(in, bytes); return (((bytes[0] & 0xff) << 32) + ((bytes[1] & 0xff) << 16) + ((bytes[2] & 0xff) << 8) + ((bytes[3] & 0xff) << 0)); } public static long u32(InputStream in) throws IOException { byte bytes[] = new byte[4]; full(in, bytes); return (((long)(bytes[0] & 0xff) << 32) + ((long)(bytes[1] & 0xff) << 16) + ((long)(bytes[2] & 0xff) << 8) + ((long)(bytes[3] & 0xff) << 0)); } public static long i64(InputStream in) throws IOException { byte bytes[] = new byte[8]; full(in, bytes); return (((long)(bytes[0] & 0xff) << 56) + ((long)(bytes[1] & 0xff) << 48) + ((long)(bytes[2] & 0xff) << 40) + ((long)(bytes[3] & 0xff) << 32) + ((long)(bytes[4] & 0xff) << 24) + ((long)(bytes[5] & 0xff) << 16) + ((long)(bytes[6] & 0xff) << 8) + ((long)(bytes[7] & 0xff) << 0)); } public static BigInteger u64(InputStream in) throws IOException { byte bytes[] = new byte[8]; full(in, bytes); return BigInteger.valueOf(0) .add(BigInteger.valueOf(bytes[0] & 0xff).shiftLeft(56)) .add(BigInteger.valueOf(bytes[1] & 0xff).shiftLeft(48)) .add(BigInteger.valueOf(bytes[2] & 0xff).shiftLeft(40)) .add(BigInteger.valueOf(bytes[3] & 0xff).shiftLeft(32)) .add(BigInteger.valueOf(bytes[4] & 0xff).shiftLeft(24)) .add(BigInteger.valueOf(bytes[5] & 0xff).shiftLeft(16)) .add(BigInteger.valueOf(bytes[6] & 0xff).shiftLeft( 8)) .add(BigInteger.valueOf(bytes[7] & 0xff).shiftLeft( 0)); } public static float f32(InputStream in) throws IOException { return Float.intBitsToFloat(i32(in)); } public static double f64(InputStream in) throws IOException { return Double.longBitsToDouble(i64(in)); } public static int[] u10x4(InputStream in) throws IOException { byte bytes[] = new byte[5]; full(in, bytes); return new int[]{ ((bytes[0] & 0b1111_1111) << 2)+ ((bytes[1] & 0b1100_0000) >> 6), ((bytes[1] & 0b0011_1111) << 4)+ ((bytes[2] & 0b1111_0000) >> 4), ((bytes[2] & 0b0000_1111) << 6)+ ((bytes[3] & 0b1111_1100) >> 2), ((bytes[3] & 0b0000_1111) << 8)+ ((bytes[4] & 0b1111_1111) >> 0), }; } public static final Instant LABVIEW_EPOCH = Instant.parse("1904-01-01T00:00:00.00Z"); /** * @bug LabVIEW timestamps have greater precision * (sub-attosecond) than Java time.Instant (nanosecond) * or Java util.Date (millisecond), so converting to a * native Java timestamp necessarily loses some * precision. * * @see http://www.ni.com/tutorial/7900/en/ */ public static Instant LVTimestamp(InputStream in) throws IOException { // seconds since the epoch 01/01/1904 00:00:00.00 UTC // (using the Gregorian calendar and ignoring leap // seconds), long secs = i64(in); // positive fractions of a second; 2¯⁶⁴ths of a second BigInteger frac = u64(in); // To get from (2¯⁶⁴s to ns, we need to divide by // precisely 18446744073.709551616 (=10¯⁹/2¯⁶⁴)... but // rounding up already gives us sub-nanosecond // precision, so don't worry about the .709... long nanos = frac.divide(BigInteger.valueOf(18446744074L)).longValue(); return LABVIEW_EPOCH.plusSeconds(secs).plusNanos(nanos); } public static String LVString(InputStream in) throws IOException { int len = i32(in); byte[] bytes = new byte[len]; full(in, bytes); return new String(bytes); } }