-
Notifications
You must be signed in to change notification settings - Fork 388
/
frame.dart
226 lines (196 loc) · 5.95 KB
/
frame.dart
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
import 'dart:typed_data';
import 'package:hive/hive.dart';
import 'package:hive/src/binary/binary_reader_impl.dart';
import 'package:hive/src/binary/binary_writer_impl.dart';
import 'package:hive/src/crypto.dart';
import 'package:hive/src/util/crc32.dart';
/// Frame
/// --------------------------
/// | uint32 frame length (including these 4 bytes and checksum)
/// --------------------------
/// | uint8 key length
/// | List<uint8> ascii key
/// -------------------------- (optional)
/// | uint8 value type
/// | List<uint8> value bytes
/// --------------------------
/// | uint32 checksum
/// --------------------------
///
/// int
/// --------------------------
/// | int64 value
/// --------------------------
///
/// double
/// --------------------------
/// | float64 value
/// --------------------------
///
/// bool
/// --------------------------
/// | uint8 value
/// --------------------------
///
/// string
/// --------------------------
/// | uint16 length
/// | List<uint8> char
/// --------------------------
///
/// list
/// --------------------------
/// | uint16 length
/// | uint8 value1 type
/// | List<uint8> value1 bytes
/// | ...
/// | uint8 valueN type
/// | List<uint8> valueN bytes
/// --------------------------
///
/// map
/// --------------------------
/// | uint16 length
/// | uint8 key1 type
/// | List<uint8> key1 bytes
/// | uint8 value1 type
/// | List<uint8> value1 bytes
/// | ...
/// | uint8 keyN type
/// | List<uint8> keyN bytes
/// | uint8 valueN type
/// | List<uint8> valueN bytes
/// --------------------------
class Frame {
static const maxFrameLength = 1000 * 64;
final String key;
final dynamic value;
final int length;
final bool overrideExisting;
const Frame(this.key, this.value, [this.length]) : overrideExisting = false;
const Frame.override(this.key, this.value, [this.length])
: overrideExisting = true;
bool get deleted => value == null;
static Frame fromBytes(
Uint8List bytes, TypeRegistry registry, Crypto crypto) {
var lengthBytes = Uint8List.view(bytes.buffer, 0, 4);
var frameBytes = Uint8List.view(bytes.buffer, 4);
checkCrc(lengthBytes, frameBytes, crypto?.keyCrc);
var frameReader =
BinaryReaderImpl(frameBytes, registry, frameBytes.length - 4);
return decodeBody(frameReader, true, true, bytes.length, crypto);
}
static Frame bodyFromBytes(
Uint8List bytes, TypeRegistry registry, Crypto crypto) {
checkCrc(null, bytes, crypto?.keyCrc);
var frameReader = BinaryReaderImpl(bytes, registry, bytes.length - 4);
return decodeBody(frameReader, false, true, bytes.length, crypto);
}
static Frame decodeBody(
BinaryReaderImpl reader,
bool decodeKey,
bool decodeValue,
int frameLength,
Crypto crypto,
) {
String key;
if (decodeKey) {
var keyLength = reader.readByte(); // Read length of key
key = reader.readAsciiString(keyLength); // Read key
}
if (reader.availableBytes == 0) {
return Frame(key, null, frameLength);
} else if (decodeValue) {
dynamic value;
if (crypto == null) {
value = reader.read();
} else {
var encryptedBytes = reader.viewBytes(reader.availableBytes);
var decryptedBytes = crypto.decrypt(encryptedBytes);
var valueReader = BinaryReaderImpl(decryptedBytes, reader.typeRegistry);
value = valueReader.read();
}
if (reader.availableBytes > 0) {
throw HiveError('Not all bytes have been used.');
}
return Frame(key, value, frameLength);
} else {
return Frame(key, null, frameLength);
}
}
static void checkCrc(
List<int> lengthBytes, List<int> frameBytes, int keyCrc) {
var computedCrc = keyCrc ?? 0;
if (lengthBytes != null) {
computedCrc = Crc32.compute(lengthBytes, crc: computedCrc);
}
computedCrc = Crc32.compute(frameBytes,
crc: computedCrc, length: frameBytes.length - 4);
var crc = bytesToUint32(frameBytes, frameBytes.length - 4);
if (computedCrc != crc) {
throw HiveError('Wrong checksum in hive file. Box may be corrupted.');
}
}
Uint8List toBytes(
bool writeKeyAndLength, TypeRegistry registry, Crypto crypto) {
if (key.length > 255) {
throw HiveError('Key must not be longer than 255 characters');
}
var writer = BinaryWriterImpl(registry);
if (writeKeyAndLength) {
writer
..writeByteList([0, 0, 0, 0],
writeLength: false) // Placeholder for length
..writeByte(key.length) // Write key length
..writeAsciiString(key, writeLength: false); // Write key
}
if (!deleted) {
if (crypto == null) {
writer.write(value); // Write value
} else {
var valueWriter = BinaryWriterImpl(writer.typeRegistry)..write(value);
var encryptedValue = crypto.encrypt(valueWriter.output());
writer.writeByteList(encryptedValue, writeLength: false);
}
}
writer
.writeByteList([0, 0, 0, 0], writeLength: false); // Placeholder for CRC
var bytes = writer.output();
var byteData = ByteData.view(bytes.buffer);
if (writeKeyAndLength) {
byteData.setUint32(0, bytes.length, Endian.little); // Write length
}
var bytesWithoutCRC = Uint8List.view(bytes.buffer, 0, bytes.length - 4);
var checksum = Crc32.compute(bytesWithoutCRC, crc: crypto?.keyCrc ?? 0);
byteData.setUint32(bytes.length - 4, checksum, Endian.little);
return bytes;
}
@override
bool operator ==(dynamic other) {
if (other is Frame) {
return other.key == key && other.value == value && other.length == length;
}
return false;
}
}
typedef ByteSource = Future<List<int>> Function(int bytes);
enum FrameValueType {
nullT,
intT,
doubleT,
boolT,
stringT,
byteListT,
intListT,
doubleListT,
boolListT,
stringListT,
listT,
mapT,
}
int bytesToUint32(List<int> bytes, [int offset = 0]) {
return bytes[offset] |
bytes[offset + 1] << 8 |
bytes[offset + 2] << 16 |
bytes[offset + 3] << 24;
}