1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.encode = encode;
|
4 | exports.decode = decode;
|
5 | exports.decodeWithLists = decodeWithLists;
|
6 | exports.decodeList = decodeList;
|
7 | exports.readUInt64LE = readUInt64LE;
|
8 | exports.writeUInt32 = writeUInt32;
|
9 | exports.readUInt32 = readUInt32;
|
10 | exports.writeFloat32LE = writeFloat32LE;
|
11 | exports.writeUInt16 = writeUInt16;
|
12 | exports.readUInt16 = readUInt16;
|
13 | exports.readVariableUIntLE = readVariableUIntLE;
|
14 | exports.writeVariableUIntLE = writeVariableUIntLE;
|
15 | const tslib_1 = require("tslib");
|
16 | const assert_1 = tslib_1.__importDefault(require("assert"));
|
17 | const hapCrypto = tslib_1.__importStar(require("../util/hapCrypto"));
|
18 |
|
19 |
|
20 |
|
21 |
|
22 | const EMPTY_TLV_TYPE = 0x00;
|
23 |
|
24 |
|
25 |
|
26 |
|
27 | function encode(type, data, ...args) {
|
28 | const encodedTLVBuffers = [];
|
29 |
|
30 | if (typeof data === "number") {
|
31 | data = Buffer.from([data]);
|
32 | }
|
33 | else if (typeof data === "string") {
|
34 | data = Buffer.from(data);
|
35 | }
|
36 | if (Array.isArray(data)) {
|
37 | let first = true;
|
38 | for (const entry of data) {
|
39 | if (!first) {
|
40 | encodedTLVBuffers.push(Buffer.from([EMPTY_TLV_TYPE, 0]));
|
41 | }
|
42 | first = false;
|
43 | encodedTLVBuffers.push(encode(type, entry));
|
44 | }
|
45 | if (first) {
|
46 | encodedTLVBuffers.push(Buffer.from([type, 0]));
|
47 | }
|
48 | }
|
49 | else if (data.length <= 255) {
|
50 | encodedTLVBuffers.push(Buffer.concat([Buffer.from([type, data.length]), data]));
|
51 | }
|
52 | else {
|
53 | let leftBytes = data.length;
|
54 | let currentIndex = 0;
|
55 | for (; leftBytes > 0;) {
|
56 | if (leftBytes >= 255) {
|
57 | encodedTLVBuffers.push(Buffer.concat([Buffer.from([type, 0xFF]), data.slice(currentIndex, currentIndex + 255)]));
|
58 | leftBytes -= 255;
|
59 | currentIndex += 255;
|
60 | }
|
61 | else {
|
62 | encodedTLVBuffers.push(Buffer.concat([Buffer.from([type, leftBytes]), data.slice(currentIndex)]));
|
63 | leftBytes -= leftBytes;
|
64 | }
|
65 | }
|
66 | }
|
67 |
|
68 | if (args.length >= 2) {
|
69 |
|
70 | const [nextType, nextData, ...nextArgs] = args;
|
71 | const remainingTLVBuffer = encode(nextType, nextData, ...nextArgs);
|
72 |
|
73 | encodedTLVBuffers.push(remainingTLVBuffer);
|
74 | }
|
75 | return Buffer.concat(encodedTLVBuffers);
|
76 | }
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 | function decode(buffer) {
|
89 | (0, assert_1.default)(buffer instanceof Buffer, "Illegal argument. tlv.decode() expects Buffer type!");
|
90 | const objects = {};
|
91 | let leftLength = buffer.length;
|
92 | let currentIndex = 0;
|
93 | for (; leftLength > 0;) {
|
94 | const type = buffer[currentIndex];
|
95 | const length = buffer[currentIndex + 1];
|
96 | currentIndex += 2;
|
97 | leftLength -= 2;
|
98 | const data = buffer.slice(currentIndex, currentIndex + length);
|
99 | if (objects[type]) {
|
100 | objects[type] = Buffer.concat([objects[type], data]);
|
101 | }
|
102 | else {
|
103 | objects[type] = data;
|
104 | }
|
105 | currentIndex += length;
|
106 | leftLength -= length;
|
107 | }
|
108 | return objects;
|
109 | }
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 | function decodeWithLists(buffer) {
|
120 | const result = {};
|
121 | let leftBytes = buffer.length;
|
122 | let readIndex = 0;
|
123 | let lastType = -1;
|
124 | let lastLength = -1;
|
125 | let lastItemWasDelimiter = false;
|
126 | for (; leftBytes > 0;) {
|
127 | const type = buffer.readUInt8(readIndex++);
|
128 | const length = buffer.readUInt8(readIndex++);
|
129 | leftBytes -= 2;
|
130 | const data = buffer.slice(readIndex, readIndex + length);
|
131 | readIndex += length;
|
132 | leftBytes -= length;
|
133 | if (type === 0 && length === 0) {
|
134 | lastItemWasDelimiter = true;
|
135 | continue;
|
136 | }
|
137 | const existing = result[type];
|
138 | if (existing) {
|
139 | if (lastItemWasDelimiter && lastType === type) {
|
140 | if (Array.isArray(existing)) {
|
141 | existing.push(data);
|
142 | }
|
143 | else {
|
144 | result[type] = [existing, data];
|
145 | }
|
146 | }
|
147 | else if (lastType === type && lastLength === 255) {
|
148 | if (Array.isArray(existing)) {
|
149 |
|
150 | const last = existing[existing.length - 1];
|
151 | existing[existing.length - 1] = Buffer.concat([last, data]);
|
152 | }
|
153 | else {
|
154 | result[type] = Buffer.concat([existing, data]);
|
155 | }
|
156 | }
|
157 | else {
|
158 | throw new Error(`Found duplicated tlv entry with type ${type} and length ${length} `
|
159 | + `(lastItemWasDelimiter: ${lastItemWasDelimiter}, lastType: ${lastType}, lastLength: ${lastLength})`);
|
160 | }
|
161 | }
|
162 | else {
|
163 | result[type] = data;
|
164 | }
|
165 | lastType = type;
|
166 | lastLength = length;
|
167 | lastItemWasDelimiter = false;
|
168 | }
|
169 | return result;
|
170 | }
|
171 |
|
172 |
|
173 |
|
174 |
|
175 |
|
176 |
|
177 |
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 |
|
184 |
|
185 | function decodeList(data, entryStartId) {
|
186 | const objectsList = [];
|
187 | let leftLength = data.length;
|
188 | let currentIndex = 0;
|
189 | let objects = undefined;
|
190 | for (; leftLength > 0;) {
|
191 | const type = data[currentIndex];
|
192 | const length = data[currentIndex + 1];
|
193 | const value = data.slice(currentIndex + 2, currentIndex + 2 + length);
|
194 | if (type === entryStartId) {
|
195 | if (objects !== undefined) {
|
196 | objectsList.push(objects);
|
197 | }
|
198 | objects = {};
|
199 | }
|
200 | if (objects === undefined) {
|
201 | throw new Error("Error parsing tlv list: Encountered uninitialized storage object");
|
202 | }
|
203 | if (objects[type]) {
|
204 | objects[type] = Buffer.concat([objects[type], value]);
|
205 | }
|
206 | else {
|
207 | objects[type] = value;
|
208 | }
|
209 | currentIndex += 2 + length;
|
210 | leftLength -= 2 + length;
|
211 | }
|
212 | if (objects !== undefined) {
|
213 | objectsList.push(objects);
|
214 | }
|
215 | return objectsList;
|
216 | }
|
217 |
|
218 |
|
219 |
|
220 | function readUInt64LE(buffer, offset = 0) {
|
221 | const low = buffer.readUInt32LE(offset);
|
222 |
|
223 | return buffer.readUInt32LE(offset + 4) * 0x100000000 + low;
|
224 | }
|
225 |
|
226 |
|
227 |
|
228 |
|
229 | function writeUInt32(value) {
|
230 | const buffer = Buffer.alloc(4);
|
231 | buffer.writeUInt32LE(value, 0);
|
232 | return buffer;
|
233 | }
|
234 |
|
235 |
|
236 |
|
237 |
|
238 | function readUInt32(buffer) {
|
239 | return buffer.readUInt32LE(0);
|
240 | }
|
241 |
|
242 |
|
243 |
|
244 | function writeFloat32LE(value) {
|
245 | const buffer = Buffer.alloc(4);
|
246 | buffer.writeFloatLE(value, 0);
|
247 | return buffer;
|
248 | }
|
249 |
|
250 |
|
251 |
|
252 |
|
253 | function writeUInt16(value) {
|
254 | const buffer = Buffer.alloc(2);
|
255 | buffer.writeUInt16LE(value, 0);
|
256 | return buffer;
|
257 | }
|
258 |
|
259 |
|
260 |
|
261 |
|
262 | function readUInt16(buffer) {
|
263 | return buffer.readUInt16LE(0);
|
264 | }
|
265 |
|
266 |
|
267 |
|
268 |
|
269 |
|
270 | function readVariableUIntLE(buffer) {
|
271 | switch (buffer.length) {
|
272 | case 1:
|
273 | return buffer.readUInt8(0);
|
274 | case 2:
|
275 | return buffer.readUInt16LE(0);
|
276 | case 4:
|
277 | return buffer.readUInt32LE(0);
|
278 | case 8:
|
279 | return readUInt64LE(buffer, 0);
|
280 | default:
|
281 | throw new Error("Can't read uint LE with length " + buffer.length);
|
282 | }
|
283 | }
|
284 |
|
285 |
|
286 |
|
287 |
|
288 |
|
289 |
|
290 |
|
291 |
|
292 |
|
293 | function writeVariableUIntLE(number) {
|
294 | (0, assert_1.default)(number >= 0, "Can't encode a negative integer as unsigned integer");
|
295 | if (number <= 255) {
|
296 | const buffer = Buffer.alloc(1);
|
297 | buffer.writeUInt8(number, 0);
|
298 | return buffer;
|
299 | }
|
300 | else if (number <= 65535) {
|
301 | return writeUInt16(number);
|
302 | }
|
303 | else if (number <= 4294967295) {
|
304 | return writeUInt32(number);
|
305 | }
|
306 | else {
|
307 | const buffer = Buffer.alloc(8);
|
308 | hapCrypto.writeUInt64LE(number, buffer, 0);
|
309 | return buffer;
|
310 | }
|
311 | }
|
312 |
|
\ | No newline at end of file |