UNPKG

homebridge-plugin-wrapper

Version:

Wrapper for Homebridge and NodeJS-HAP with reduced dependencies that allows to intercept plugin values and also send to them

887 lines 36.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DataStreamWriter = exports.DataStreamReader = exports.DataStreamParser = exports.DataFormatTags = exports.UUID = exports.SecondsSince2001 = exports.Float64 = exports.Float32 = exports.Int64 = exports.Int32 = exports.Int16 = exports.Int8 = exports.ValueWrapper = void 0; var tslib_1 = require("tslib"); var uuid = (0, tslib_1.__importStar)(require("../util/uuid")); var hapCrypto = (0, tslib_1.__importStar)(require("../util/hapCrypto")); var assert_1 = (0, tslib_1.__importDefault)(require("assert")); var debug_1 = (0, tslib_1.__importDefault)(require("debug")); // welcome to hell :) // in this file lies madness and frustration. and It's not only about HDS. Also, JavaScript is hell var debug = (0, debug_1.default)("HAP-NodeJS:DataStream:Parser"); var Magics = /** @class */ (function () { function Magics() { } Magics.TERMINATOR = { type: "terminator" }; return Magics; }()); var ValueWrapper = /** @class */ (function () { function ValueWrapper(value) { this.value = value; } ValueWrapper.prototype.equals = function (obj) { return this.constructor.name === obj.constructor.name && obj.value === this.value; }; return ValueWrapper; }()); exports.ValueWrapper = ValueWrapper; var Int8 = /** @class */ (function (_super) { (0, tslib_1.__extends)(Int8, _super); function Int8() { return _super !== null && _super.apply(this, arguments) || this; } return Int8; }(ValueWrapper)); exports.Int8 = Int8; var Int16 = /** @class */ (function (_super) { (0, tslib_1.__extends)(Int16, _super); function Int16() { return _super !== null && _super.apply(this, arguments) || this; } return Int16; }(ValueWrapper)); exports.Int16 = Int16; var Int32 = /** @class */ (function (_super) { (0, tslib_1.__extends)(Int32, _super); function Int32() { return _super !== null && _super.apply(this, arguments) || this; } return Int32; }(ValueWrapper)); exports.Int32 = Int32; var Int64 = /** @class */ (function (_super) { (0, tslib_1.__extends)(Int64, _super); function Int64() { return _super !== null && _super.apply(this, arguments) || this; } return Int64; }(ValueWrapper)); exports.Int64 = Int64; var Float32 = /** @class */ (function (_super) { (0, tslib_1.__extends)(Float32, _super); function Float32() { return _super !== null && _super.apply(this, arguments) || this; } return Float32; }(ValueWrapper)); exports.Float32 = Float32; var Float64 = /** @class */ (function (_super) { (0, tslib_1.__extends)(Float64, _super); function Float64() { return _super !== null && _super.apply(this, arguments) || this; } return Float64; }(ValueWrapper)); exports.Float64 = Float64; var SecondsSince2001 = /** @class */ (function (_super) { (0, tslib_1.__extends)(SecondsSince2001, _super); function SecondsSince2001() { return _super !== null && _super.apply(this, arguments) || this; } return SecondsSince2001; }(ValueWrapper)); exports.SecondsSince2001 = SecondsSince2001; var UUID = /** @class */ (function (_super) { (0, tslib_1.__extends)(UUID, _super); function UUID(value) { var _this = this; (0, assert_1.default)(uuid.isValid(value), "invalid uuid format"); _this = _super.call(this, value) || this; return _this; } return UUID; }(ValueWrapper)); exports.UUID = UUID; var DataFormatTags; (function (DataFormatTags) { DataFormatTags[DataFormatTags["INVALID"] = 0] = "INVALID"; DataFormatTags[DataFormatTags["TRUE"] = 1] = "TRUE"; DataFormatTags[DataFormatTags["FALSE"] = 2] = "FALSE"; DataFormatTags[DataFormatTags["TERMINATOR"] = 3] = "TERMINATOR"; DataFormatTags[DataFormatTags["NULL"] = 4] = "NULL"; DataFormatTags[DataFormatTags["UUID"] = 5] = "UUID"; DataFormatTags[DataFormatTags["DATE"] = 6] = "DATE"; DataFormatTags[DataFormatTags["INTEGER_MINUS_ONE"] = 7] = "INTEGER_MINUS_ONE"; DataFormatTags[DataFormatTags["INTEGER_RANGE_START_0"] = 8] = "INTEGER_RANGE_START_0"; DataFormatTags[DataFormatTags["INTEGER_RANGE_STOP_39"] = 46] = "INTEGER_RANGE_STOP_39"; DataFormatTags[DataFormatTags["INT8"] = 48] = "INT8"; DataFormatTags[DataFormatTags["INT16LE"] = 49] = "INT16LE"; DataFormatTags[DataFormatTags["INT32LE"] = 50] = "INT32LE"; DataFormatTags[DataFormatTags["INT64LE"] = 51] = "INT64LE"; DataFormatTags[DataFormatTags["FLOAT32LE"] = 53] = "FLOAT32LE"; DataFormatTags[DataFormatTags["FLOAT64LE"] = 54] = "FLOAT64LE"; DataFormatTags[DataFormatTags["UTF8_LENGTH_START"] = 64] = "UTF8_LENGTH_START"; DataFormatTags[DataFormatTags["UTF8_LENGTH_STOP"] = 96] = "UTF8_LENGTH_STOP"; DataFormatTags[DataFormatTags["UTF8_LENGTH8"] = 97] = "UTF8_LENGTH8"; DataFormatTags[DataFormatTags["UTF8_LENGTH16LE"] = 98] = "UTF8_LENGTH16LE"; DataFormatTags[DataFormatTags["UTF8_LENGTH32LE"] = 99] = "UTF8_LENGTH32LE"; DataFormatTags[DataFormatTags["UTF8_LENGTH64LE"] = 100] = "UTF8_LENGTH64LE"; DataFormatTags[DataFormatTags["UTF8_NULL_TERMINATED"] = 111] = "UTF8_NULL_TERMINATED"; DataFormatTags[DataFormatTags["DATA_LENGTH_START"] = 112] = "DATA_LENGTH_START"; DataFormatTags[DataFormatTags["DATA_LENGTH_STOP"] = 144] = "DATA_LENGTH_STOP"; DataFormatTags[DataFormatTags["DATA_LENGTH8"] = 145] = "DATA_LENGTH8"; DataFormatTags[DataFormatTags["DATA_LENGTH16LE"] = 146] = "DATA_LENGTH16LE"; DataFormatTags[DataFormatTags["DATA_LENGTH32LE"] = 147] = "DATA_LENGTH32LE"; DataFormatTags[DataFormatTags["DATA_LENGTH64LE"] = 148] = "DATA_LENGTH64LE"; DataFormatTags[DataFormatTags["DATA_TERMINATED"] = 159] = "DATA_TERMINATED"; DataFormatTags[DataFormatTags["COMPRESSION_START"] = 160] = "COMPRESSION_START"; DataFormatTags[DataFormatTags["COMPRESSION_STOP"] = 207] = "COMPRESSION_STOP"; DataFormatTags[DataFormatTags["ARRAY_LENGTH_START"] = 208] = "ARRAY_LENGTH_START"; DataFormatTags[DataFormatTags["ARRAY_LENGTH_STOP"] = 222] = "ARRAY_LENGTH_STOP"; DataFormatTags[DataFormatTags["ARRAY_TERMINATED"] = 223] = "ARRAY_TERMINATED"; DataFormatTags[DataFormatTags["DICTIONARY_LENGTH_START"] = 224] = "DICTIONARY_LENGTH_START"; DataFormatTags[DataFormatTags["DICTIONARY_LENGTH_STOP"] = 238] = "DICTIONARY_LENGTH_STOP"; DataFormatTags[DataFormatTags["DICTIONARY_TERMINATED"] = 239] = "DICTIONARY_TERMINATED"; })(DataFormatTags = exports.DataFormatTags || (exports.DataFormatTags = {})); var DataStreamParser = /** @class */ (function () { function DataStreamParser() { } // eslint-disable-next-line @typescript-eslint/no-explicit-any DataStreamParser.decode = function (buffer) { var tag = buffer.readTag(); if (tag === 0 /* INVALID */) { throw new Error("HDSDecoder: zero tag detected on index " + buffer.readerIndex); } else if (tag === 1 /* TRUE */) { return buffer.readTrue(); } else if (tag === 2 /* FALSE */) { return buffer.readFalse(); } else if (tag === 3 /* TERMINATOR */) { return Magics.TERMINATOR; } else if (tag === 4 /* NULL */) { return null; } else if (tag === 5 /* UUID */) { return buffer.readUUID(); } else if (tag === 6 /* DATE */) { return buffer.readSecondsSince2001_01_01(); } else if (tag === 7 /* INTEGER_MINUS_ONE */) { return buffer.readNegOne(); } else if (tag >= 8 /* INTEGER_RANGE_START_0 */ && tag <= 46 /* INTEGER_RANGE_STOP_39 */) { return buffer.readIntRange(tag); // integer values from 0-39 } else if (tag === 48 /* INT8 */) { return buffer.readInt8(); } else if (tag === 49 /* INT16LE */) { return buffer.readInt16LE(); } else if (tag === 50 /* INT32LE */) { return buffer.readInt32LE(); } else if (tag === 51 /* INT64LE */) { return buffer.readInt64LE(); } else if (tag === 53 /* FLOAT32LE */) { return buffer.readFloat32LE(); } else if (tag === 54 /* FLOAT64LE */) { return buffer.readFloat64LE(); } else if (tag >= 64 /* UTF8_LENGTH_START */ && tag <= 96 /* UTF8_LENGTH_STOP */) { var length = tag - 64 /* UTF8_LENGTH_START */; return buffer.readUTF8(length); } else if (tag === 97 /* UTF8_LENGTH8 */) { return buffer.readUTF8_Length8(); } else if (tag === 98 /* UTF8_LENGTH16LE */) { return buffer.readUTF8_Length16LE(); } else if (tag === 99 /* UTF8_LENGTH32LE */) { return buffer.readUTF8_Length32LE(); } else if (tag === 100 /* UTF8_LENGTH64LE */) { return buffer.readUTF8_Length64LE(); } else if (tag === 111 /* UTF8_NULL_TERMINATED */) { return buffer.readUTF8_NULL_terminated(); } else if (tag >= 112 /* DATA_LENGTH_START */ && tag <= 144 /* DATA_LENGTH_STOP */) { var length = tag - 112 /* DATA_LENGTH_START */; buffer.readData(length); } else if (tag === 145 /* DATA_LENGTH8 */) { return buffer.readData_Length8(); } else if (tag === 146 /* DATA_LENGTH16LE */) { return buffer.readData_Length16LE(); } else if (tag === 147 /* DATA_LENGTH32LE */) { return buffer.readData_Length32LE(); } else if (tag === 148 /* DATA_LENGTH64LE */) { return buffer.readData_Length64LE(); } else if (tag === 159 /* DATA_TERMINATED */) { return buffer.readData_terminated(); } else if (tag >= 160 /* COMPRESSION_START */ && tag <= 207 /* COMPRESSION_STOP */) { var index = tag - 160 /* COMPRESSION_START */; return buffer.decompressData(index); } else if (tag >= 208 /* ARRAY_LENGTH_START */ && tag <= 222 /* ARRAY_LENGTH_STOP */) { var length = tag - 208 /* ARRAY_LENGTH_START */; var array = []; for (var i = 0; i < length; i++) { array.push(this.decode(buffer)); } return array; } else if (tag === 223 /* ARRAY_TERMINATED */) { var array = []; var element = void 0; while ((element = this.decode(buffer)) !== Magics.TERMINATOR) { array.push(element); } return array; } else if (tag >= 224 /* DICTIONARY_LENGTH_START */ && tag <= 238 /* DICTIONARY_LENGTH_STOP */) { var length = tag - 224 /* DICTIONARY_LENGTH_START */; // eslint-disable-next-line @typescript-eslint/no-explicit-any var dictionary = {}; for (var i = 0; i < length; i++) { var key = this.decode(buffer); dictionary[key] = this.decode(buffer); } return dictionary; } else if (tag === 239 /* DICTIONARY_TERMINATED */) { // eslint-disable-next-line @typescript-eslint/no-explicit-any var dictionary = {}; var key = void 0; while ((key = this.decode(buffer)) !== Magics.TERMINATOR) { dictionary[key] = this.decode(buffer); // decode value } return dictionary; } else { throw new Error("HDSDecoder: encountered unknown tag on index " + buffer.readerIndex + ": " + tag.toString(16)); } }; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types,@typescript-eslint/no-explicit-any DataStreamParser.encode = function (data, buffer) { var _this = this; if (data === undefined) { throw new Error("HDSEncoder: cannot encode undefined"); } if (data === null) { buffer.writeTag(4 /* NULL */); return; } switch (typeof data) { case "boolean": if (data) { buffer.writeTrue(); } else { buffer.writeFalse(); } break; case "number": if (Number.isInteger(data)) { buffer.writeNumber(data); } else { buffer.writeFloat64LE(new Float64(data)); } break; case "string": buffer.writeUTF8(data); break; case "object": if (Array.isArray(data)) { var length = data.length; if (length <= 12) { buffer.writeTag(208 /* ARRAY_LENGTH_START */ + length); } else { buffer.writeTag(223 /* ARRAY_TERMINATED */); } data.forEach(function (element) { _this.encode(element, buffer); }); if (length > 12) { buffer.writeTag(3 /* TERMINATOR */); } } else if (data instanceof ValueWrapper) { if (data instanceof Int8) { buffer.writeInt8(data); } else if (data instanceof Int16) { buffer.writeInt16LE(data); } else if (data instanceof Int32) { buffer.writeInt32LE(data); } else if (data instanceof Int64) { buffer.writeInt64LE(data); } else if (data instanceof Float32) { buffer.writeFloat32LE(data); } else if (data instanceof Float64) { buffer.writeFloat64LE(data); } else if (data instanceof SecondsSince2001) { buffer.writeSecondsSince2001_01_01(data); } else if (data instanceof UUID) { buffer.writeUUID(data.value); } else { throw new Error("Unknown wrapped object 'ValueWrapper' of class " + data.constructor.name); } } else if (data instanceof Buffer) { buffer.writeData(data); } else { // object is treated as dictionary var entries = Object.entries(data) .filter(function (entry) { return entry[1] !== undefined; }); // explicitly setting undefined will result in an entry here if (entries.length <= 14) { buffer.writeTag(224 /* DICTIONARY_LENGTH_START */ + entries.length); } else { buffer.writeTag(239 /* DICTIONARY_TERMINATED */); } entries.forEach(function (entry) { _this.encode(entry[0], buffer); // encode key _this.encode(entry[1], buffer); // encode value }); if (entries.length > 14) { buffer.writeTag(3 /* TERMINATOR */); } } break; default: throw new Error("HDSEncoder: no idea how to encode value of type '" + (typeof data) + "': " + data); } }; return DataStreamParser; }()); exports.DataStreamParser = DataStreamParser; var DataStreamReader = /** @class */ (function () { function DataStreamReader(data) { // eslint-disable-next-line @typescript-eslint/no-explicit-any this.trackedCompressedData = []; this.data = data; this.readerIndex = 0; } DataStreamReader.prototype.finished = function () { if (this.readerIndex < this.data.length) { var remainingHex = this.data.slice(this.readerIndex, this.data.length).toString("hex"); debug("WARNING Finished reading HDS stream, but there are still %d bytes remaining () %s", this.data.length - this.readerIndex, remainingHex); } }; // eslint-disable-next-line @typescript-eslint/no-explicit-any DataStreamReader.prototype.decompressData = function (index) { if (index >= this.trackedCompressedData.length) { throw new Error("HDSDecoder: Tried decompression of data for an index out of range (index " + index + " and got " + this.trackedCompressedData.length + " elements)"); } return this.trackedCompressedData[index]; }; DataStreamReader.prototype.trackData = function (data) { this.trackedCompressedData.push(data); return data; }; DataStreamReader.prototype.ensureLength = function (bytes) { if (this.readerIndex + bytes > this.data.length) { var remaining = this.data.length - this.readerIndex; throw new Error("HDSDecoder: End of data stream. Tried reading " + bytes + " bytes however got only " + remaining + " remaining!"); } }; DataStreamReader.prototype.readTag = function () { this.ensureLength(1); return this.data.readUInt8(this.readerIndex++); }; DataStreamReader.prototype.readTrue = function () { return this.trackData(true); // do those tag encoded values get cached? }; DataStreamReader.prototype.readFalse = function () { return this.trackData(false); }; DataStreamReader.prototype.readNegOne = function () { return this.trackData(-1); }; DataStreamReader.prototype.readIntRange = function (tag) { return this.trackData(tag - 8 /* INTEGER_RANGE_START_0 */); // integer values from 0-39 }; DataStreamReader.prototype.readInt8 = function () { this.ensureLength(1); return this.trackData(this.data.readInt8(this.readerIndex++)); }; DataStreamReader.prototype.readInt16LE = function () { this.ensureLength(2); var value = this.data.readInt16LE(this.readerIndex); this.readerIndex += 2; return this.trackData(value); }; DataStreamReader.prototype.readInt32LE = function () { this.ensureLength(4); var value = this.data.readInt32LE(this.readerIndex); this.readerIndex += 4; return this.trackData(value); }; DataStreamReader.prototype.readInt64LE = function () { this.ensureLength(8); var low = this.data.readInt32LE(this.readerIndex); var value = this.data.readInt32LE(this.readerIndex + 4) * 0x100000000 + low; if (low < 0) { value += 0x100000000; } this.readerIndex += 8; return this.trackData(value); }; DataStreamReader.prototype.readFloat32LE = function () { this.ensureLength(4); var value = this.data.readFloatLE(this.readerIndex); this.readerIndex += 4; return this.trackData(value); }; DataStreamReader.prototype.readFloat64LE = function () { this.ensureLength(8); var value = this.data.readDoubleLE(this.readerIndex); return this.trackData(value); }; DataStreamReader.prototype.readLength8 = function () { this.ensureLength(1); return this.data.readUInt8(this.readerIndex++); }; DataStreamReader.prototype.readLength16LE = function () { this.ensureLength(2); var value = this.data.readUInt16LE(this.readerIndex); this.readerIndex += 2; return value; }; DataStreamReader.prototype.readLength32LE = function () { this.ensureLength(4); var value = this.data.readUInt32LE(this.readerIndex); this.readerIndex += 4; return value; }; DataStreamReader.prototype.readLength64LE = function () { this.ensureLength(8); var low = this.data.readUInt32LE(this.readerIndex); var value = this.data.readUInt32LE(this.readerIndex + 4) * 0x100000000 + low; this.readerIndex += 8; return value; }; DataStreamReader.prototype.readUTF8 = function (length) { this.ensureLength(length); var value = this.data.toString("utf8", this.readerIndex, this.readerIndex + length); this.readerIndex += length; return this.trackData(value); }; DataStreamReader.prototype.readUTF8_Length8 = function () { var length = this.readLength8(); return this.readUTF8(length); }; DataStreamReader.prototype.readUTF8_Length16LE = function () { var length = this.readLength16LE(); return this.readUTF8(length); }; DataStreamReader.prototype.readUTF8_Length32LE = function () { var length = this.readLength32LE(); return this.readUTF8(length); }; DataStreamReader.prototype.readUTF8_Length64LE = function () { var length = this.readLength64LE(); return this.readUTF8(length); }; DataStreamReader.prototype.readUTF8_NULL_terminated = function () { var offset = this.readerIndex; var nextByte; for (;;) { nextByte = this.data[offset]; if (nextByte === undefined) { throw new Error("HDSDecoder: Reached end of data stream while reading NUL terminated string!"); } else if (nextByte === 0) { break; } else { offset++; } } var value = this.data.toString("utf8", this.readerIndex, offset); this.readerIndex = offset + 1; return this.trackData(value); }; DataStreamReader.prototype.readData = function (length) { this.ensureLength(length); var value = this.data.slice(this.readerIndex, this.readerIndex + length); this.readerIndex += length; return this.trackData(value); }; DataStreamReader.prototype.readData_Length8 = function () { var length = this.readLength8(); return this.readData(length); }; DataStreamReader.prototype.readData_Length16LE = function () { var length = this.readLength16LE(); return this.readData(length); }; DataStreamReader.prototype.readData_Length32LE = function () { var length = this.readLength32LE(); return this.readData(length); }; DataStreamReader.prototype.readData_Length64LE = function () { var length = this.readLength64LE(); return this.readData(length); }; DataStreamReader.prototype.readData_terminated = function () { var offset = this.readerIndex; var nextByte; for (;;) { nextByte = this.data[offset]; if (nextByte === undefined) { throw new Error("HDSDecoder: Reached end of data stream while reading terminated data!"); } else if (nextByte === 3 /* TERMINATOR */) { break; } else { offset++; } } var value = this.data.slice(this.readerIndex, offset); this.readerIndex = offset + 1; return this.trackData(value); }; DataStreamReader.prototype.readSecondsSince2001_01_01 = function () { // second since 2001-01-01 00:00:00 return this.readFloat64LE(); }; DataStreamReader.prototype.readUUID = function () { this.ensureLength(16); var value = uuid.unparse(this.data, this.readerIndex); this.readerIndex += 16; return this.trackData(value); }; return DataStreamReader; }()); exports.DataStreamReader = DataStreamReader; var WrittenDataList = /** @class */ (function () { function WrittenDataList() { // eslint-disable-next-line @typescript-eslint/no-explicit-any this.writtenData = []; } WrittenDataList.prototype.push = function (data) { this.writtenData.push(data); }; WrittenDataList.prototype.indexOf = function (data) { for (var i = 0; i < this.writtenData.length; i++) { var data0 = this.writtenData[i]; if (data === data0) { return i; } if (data instanceof ValueWrapper && data0 instanceof ValueWrapper) { if (data.equals(data0)) { return i; } } } return -1; }; return WrittenDataList; }()); var DataStreamWriter = /** @class */ (function () { function DataStreamWriter() { this.writtenData = new WrittenDataList(); this.data = Buffer.alloc(DataStreamWriter.chunkSize); this.writerIndex = 0; } DataStreamWriter.prototype.length = function () { return this.writerIndex; // since writerIndex points to the next FREE index it also represents the length }; DataStreamWriter.prototype.getData = function () { return this.data.slice(0, this.writerIndex); }; DataStreamWriter.prototype.ensureLength = function (bytes) { var neededBytes = (this.writerIndex + bytes) - this.data.length; if (neededBytes > 0) { var chunks = Math.ceil(neededBytes / DataStreamWriter.chunkSize); // don't know if it's best for performance to immediately concatenate the buffers. That way it's // the easiest way to handle writing though. this.data = Buffer.concat([this.data, Buffer.alloc(chunks * DataStreamWriter.chunkSize)]); } }; DataStreamWriter.prototype.compressDataIfPossible = function (data) { var index = this.writtenData.indexOf(data); if (index < 0) { // data is not present yet this.writtenData.push(data); return false; } else if (index <= 207 /* COMPRESSION_STOP */ - 160 /* COMPRESSION_START */) { // data was already written and the index is in the applicable range => shorten the payload this.writeTag(160 /* COMPRESSION_START */ + index); return true; } return false; }; DataStreamWriter.prototype.writeTag = function (tag) { this.ensureLength(1); this.data.writeUInt8(tag, this.writerIndex++); }; DataStreamWriter.prototype.writeTrue = function () { this.writeTag(1 /* TRUE */); }; DataStreamWriter.prototype.writeFalse = function () { this.writeTag(2 /* FALSE */); }; DataStreamWriter.prototype.writeNumber = function (number) { if (number === -1) { this.writeTag(7 /* INTEGER_MINUS_ONE */); } else if (number >= 0 && number <= 39) { this.writeTag(8 /* INTEGER_RANGE_START_0 */ + number); } else if (number >= -128 && number <= 127) { this.writeInt8(new Int8(number)); } else if (number >= -32768 && number <= 32767) { this.writeInt16LE(new Int16(number)); } else if (number >= -2147483648 && number <= -2147483648) { this.writeInt32LE(new Int32(number)); } else if (number >= Number.MIN_SAFE_INTEGER && number <= Number.MAX_SAFE_INTEGER) { // use correct uin64 restriction when we convert to bigint this.writeInt64LE(new Int64(number)); } else { throw new Error("Tried writing unrepresentable number (" + number + ")"); } }; DataStreamWriter.prototype.writeInt8 = function (int8) { if (this.compressDataIfPossible(int8)) { return; } this.ensureLength(2); this.writeTag(48 /* INT8 */); this.data.writeInt8(int8.value, this.writerIndex++); }; DataStreamWriter.prototype.writeInt16LE = function (int16) { if (this.compressDataIfPossible(int16)) { return; } this.ensureLength(3); this.writeTag(49 /* INT16LE */); this.data.writeInt16LE(int16.value, this.writerIndex); this.writerIndex += 2; }; DataStreamWriter.prototype.writeInt32LE = function (int32) { if (this.compressDataIfPossible(int32)) { return; } this.ensureLength(5); this.writeTag(50 /* INT32LE */); this.data.writeInt32LE(int32.value, this.writerIndex); this.writerIndex += 4; }; DataStreamWriter.prototype.writeInt64LE = function (int64) { if (this.compressDataIfPossible(int64)) { return; } this.ensureLength(9); this.writeTag(51 /* INT64LE */); this.data.writeUInt32LE(int64.value, this.writerIndex); // TODO correctly implement int64; currently it's basically an int32 this.data.writeUInt32LE(0, this.writerIndex + 4); this.writerIndex += 8; }; DataStreamWriter.prototype.writeFloat32LE = function (float32) { if (this.compressDataIfPossible(float32)) { return; } this.ensureLength(5); this.writeTag(53 /* FLOAT32LE */); this.data.writeFloatLE(float32.value, this.writerIndex); this.writerIndex += 4; }; DataStreamWriter.prototype.writeFloat64LE = function (float64) { if (this.compressDataIfPossible(float64)) { return; } this.ensureLength(9); this.writeTag(54 /* FLOAT64LE */); this.data.writeDoubleLE(float64.value, this.writerIndex); this.writerIndex += 8; }; DataStreamWriter.prototype.writeLength8 = function (length) { this.ensureLength(1); this.data.writeUInt8(length, this.writerIndex++); }; DataStreamWriter.prototype.writeLength16LE = function (length) { this.ensureLength(2); this.data.writeUInt16LE(length, this.writerIndex); this.writerIndex += 2; }; DataStreamWriter.prototype.writeLength32LE = function (length) { this.ensureLength(4); this.data.writeUInt32LE(length, this.writerIndex); this.writerIndex += 4; }; DataStreamWriter.prototype.writeLength64LE = function (length) { this.ensureLength(8); hapCrypto.writeUInt64LE(length, this.data, this.writerIndex); this.writerIndex += 8; }; DataStreamWriter.prototype.writeUTF8 = function (utf8) { if (this.compressDataIfPossible(utf8)) { return; } var length = Buffer.byteLength(utf8); if (length <= 32) { this.ensureLength(1 + length); this.writeTag(64 /* UTF8_LENGTH_START */ + utf8.length); this._writeUTF8(utf8); } else if (length <= 255) { this.writeUTF8_Length8(utf8); } else if (length <= 65535) { this.writeUTF8_Length16LE(utf8); } else if (length <= 4294967295) { this.writeUTF8_Length32LE(utf8); } else if (length <= Number.MAX_SAFE_INTEGER) { // use correct uin64 restriction when we convert to bigint this.writeUTF8_Length64LE(utf8); } else { this.writeUTF8_NULL_terminated(utf8); } }; DataStreamWriter.prototype._writeUTF8 = function (utf8) { var byteLength = Buffer.byteLength(utf8); this.ensureLength(byteLength); this.data.write(utf8, this.writerIndex, undefined, "utf8"); this.writerIndex += byteLength; }; DataStreamWriter.prototype.writeUTF8_Length8 = function (utf8) { var length = Buffer.byteLength(utf8); this.ensureLength(2 + length); this.writeTag(97 /* UTF8_LENGTH8 */); this.writeLength8(length); this._writeUTF8(utf8); }; DataStreamWriter.prototype.writeUTF8_Length16LE = function (utf8) { var length = Buffer.byteLength(utf8); this.ensureLength(3 + length); this.writeTag(98 /* UTF8_LENGTH16LE */); this.writeLength16LE(length); this._writeUTF8(utf8); }; DataStreamWriter.prototype.writeUTF8_Length32LE = function (utf8) { var length = Buffer.byteLength(utf8); this.ensureLength(5 + length); this.writeTag(99 /* UTF8_LENGTH32LE */); this.writeLength32LE(length); this._writeUTF8(utf8); }; DataStreamWriter.prototype.writeUTF8_Length64LE = function (utf8) { var length = Buffer.byteLength(utf8); this.ensureLength(9 + length); this.writeTag(100 /* UTF8_LENGTH64LE */); this.writeLength64LE(length); this._writeUTF8(utf8); }; DataStreamWriter.prototype.writeUTF8_NULL_terminated = function (utf8) { this.ensureLength(1 + Buffer.byteLength(utf8) + 1); this.writeTag(111 /* UTF8_NULL_TERMINATED */); this._writeUTF8(utf8); this.data.writeUInt8(0, this.writerIndex++); }; DataStreamWriter.prototype.writeData = function (data) { if (this.compressDataIfPossible(data)) { return; } if (data.length <= 32) { this.writeTag(112 /* DATA_LENGTH_START */ + data.length); this._writeData(data); } else if (data.length <= 255) { this.writeData_Length8(data); } else if (data.length <= 65535) { this.writeData_Length16LE(data); } else if (data.length <= 4294967295) { this.writeData_Length32LE(data); } else if (data.length <= Number.MAX_SAFE_INTEGER) { this.writeData_Length64LE(data); } else { this.writeData_terminated(data); } }; DataStreamWriter.prototype._writeData = function (data) { this.ensureLength(data.length); for (var i = 0; i < data.length; i++) { this.data[this.writerIndex++] = data[i]; } }; DataStreamWriter.prototype.writeData_Length8 = function (data) { this.ensureLength(2 + data.length); this.writeTag(145 /* DATA_LENGTH8 */); this.writeLength8(data.length); this._writeData(data); }; DataStreamWriter.prototype.writeData_Length16LE = function (data) { this.ensureLength(3 + data.length); this.writeTag(146 /* DATA_LENGTH16LE */); this.writeLength16LE(data.length); this._writeData(data); }; DataStreamWriter.prototype.writeData_Length32LE = function (data) { this.ensureLength(5 + data.length); this.writeTag(147 /* DATA_LENGTH32LE */); this.writeLength32LE(data.length); this._writeData(data); }; DataStreamWriter.prototype.writeData_Length64LE = function (data) { this.ensureLength(9 + data.length); this.writeTag(148 /* DATA_LENGTH64LE */); this.writeLength64LE(data.length); this._writeData(data); }; DataStreamWriter.prototype.writeData_terminated = function (data) { this.ensureLength(1 + data.length + 1); this.writeTag(159 /* DATA_TERMINATED */); this._writeData(data); this.writeTag(3 /* TERMINATOR */); }; DataStreamWriter.prototype.writeSecondsSince2001_01_01 = function (seconds) { if (this.compressDataIfPossible(seconds)) { return; } this.ensureLength(9); this.writeTag(6 /* DATE */); this.data.writeDoubleLE(seconds.value, this.writerIndex); this.writerIndex += 8; }; DataStreamWriter.prototype.writeUUID = function (uuid_string) { (0, assert_1.default)(uuid.isValid(uuid_string), "supplied uuid is invalid"); if (this.compressDataIfPossible(new UUID(uuid_string))) { return; } this.ensureLength(17); this.writeTag(5 /* UUID */); uuid.write(uuid_string, this.data, this.writerIndex); this.writerIndex += 16; }; DataStreamWriter.chunkSize = 128; // seems to be a good default return DataStreamWriter; }()); exports.DataStreamWriter = DataStreamWriter; //# sourceMappingURL=DataStreamParser.js.map