-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBitPacker.java
More file actions
107 lines (92 loc) · 4.13 KB
/
BitPacker.java
File metadata and controls
107 lines (92 loc) · 4.13 KB
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
package com.example.bip39.bit;
import java.util.Objects;
public final class BitPacker {
private static final int ELEVEN_BIT_GROUP_SIZE = 11;
private BitPacker() {}
public static int readBits(byte[] source, int bitOffset, int bitLength) {
Objects.requireNonNull(source, "source must not be null");
validateBitAccess(source.length, bitOffset, bitLength);
if (bitLength > Integer.SIZE - 1) {
throw new IllegalArgumentException("bitLength must be at most 31");
}
int value = 0;
for (int bitIndex = 0; bitIndex < bitLength; bitIndex++) {
int absoluteBitIndex = bitOffset + bitIndex;
int byteIndex = absoluteBitIndex / Byte.SIZE;
int bitIndexInByte = 7 - (absoluteBitIndex % Byte.SIZE);
int bit = ((source[byteIndex] & 0xff) >> bitIndexInByte) & 0x01;
value = (value << 1) | bit;
}
return value;
}
public static void writeBits(byte[] target, int bitOffset, int bitLength, int value) {
Objects.requireNonNull(target, "target must not be null");
validateBitAccess(target.length, bitOffset, bitLength);
if (bitLength > Integer.SIZE - 1) {
throw new IllegalArgumentException("bitLength must be at most 31");
}
if (bitLength != 0 && value >>> bitLength != 0) {
throw new IllegalArgumentException("value does not fit into the requested bit length");
}
for (int bitIndex = 0; bitIndex < bitLength; bitIndex++) {
int absoluteBitIndex = bitOffset + bitIndex;
int byteIndex = absoluteBitIndex / Byte.SIZE;
int bitIndexInByte = 7 - (absoluteBitIndex % Byte.SIZE);
int bitMask = 1 << bitIndexInByte;
int bit = (value >> (bitLength - 1 - bitIndex)) & 0x01;
int clearedByte = target[byteIndex] & ~bitMask;
target[byteIndex] = (byte) (clearedByte | (bit << bitIndexInByte));
}
}
public static int[] splitTo11BitValues(byte[] source, int totalBitLength) {
Objects.requireNonNull(source, "source must not be null");
validateTotalBitLength(source.length, totalBitLength);
if (totalBitLength % ELEVEN_BIT_GROUP_SIZE != 0) {
throw new IllegalArgumentException("totalBitLength must be divisible by 11");
}
int[] values = new int[totalBitLength / ELEVEN_BIT_GROUP_SIZE];
for (int valueIndex = 0; valueIndex < values.length; valueIndex++) {
values[valueIndex] =
readBits(source, valueIndex * ELEVEN_BIT_GROUP_SIZE, ELEVEN_BIT_GROUP_SIZE);
}
return values;
}
public static byte[] pack11BitValues(int[] values) {
Objects.requireNonNull(values, "values must not be null");
byte[] packed = new byte[(values.length * ELEVEN_BIT_GROUP_SIZE + 7) / Byte.SIZE];
for (int valueIndex = 0; valueIndex < values.length; valueIndex++) {
int value = values[valueIndex];
if (value < 0 || value > 0x7ff) {
throw new IllegalArgumentException("11-bit value out of range: " + value);
}
writeBits(packed, valueIndex * ELEVEN_BIT_GROUP_SIZE, ELEVEN_BIT_GROUP_SIZE, value);
}
return packed;
}
public static byte[] extractBytes(byte[] source, int bitOffset, int bitLength) {
Objects.requireNonNull(source, "source must not be null");
validateBitAccess(source.length, bitOffset, bitLength);
if (bitLength % Byte.SIZE != 0) {
throw new IllegalArgumentException("bitLength must be divisible by 8");
}
byte[] bytes = new byte[bitLength / Byte.SIZE];
for (int byteIndex = 0; byteIndex < bytes.length; byteIndex++) {
bytes[byteIndex] = (byte) readBits(source, bitOffset + byteIndex * Byte.SIZE, Byte.SIZE);
}
return bytes;
}
private static void validateTotalBitLength(int sourceLengthBytes, int totalBitLength) {
validateBitAccess(sourceLengthBytes, 0, totalBitLength);
}
private static void validateBitAccess(int sourceLengthBytes, int bitOffset, int bitLength) {
if (bitOffset < 0) {
throw new IllegalArgumentException("bitOffset must not be negative");
}
if (bitLength < 0) {
throw new IllegalArgumentException("bitLength must not be negative");
}
if (bitOffset + bitLength > sourceLengthBytes * Byte.SIZE) {
throw new IllegalArgumentException("Requested bits exceed source length");
}
}
}