summaryrefslogtreecommitdiff
path: root/dslog/Read.java
blob: 04537d570d5673208ac3d172a5d8744090d6f036 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
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);
	}
}