hap-controller
Version:
Library to implement a HAP (HomeKit) controller
112 lines • 3.8 kB
JavaScript
;
/**
* Class for dealing with HAP TLV data.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.decodeBuffer = decodeBuffer;
exports.encodeObject = encodeObject;
const debug_1 = __importDefault(require("debug"));
const debug = (0, debug_1.default)('hap-controller:tlv');
const kTLVType_Separator = 255;
/**
* Decode a buffer into a TLV object.
*
* See Chapter 12.1
*
* @param {Buffer} buffer - Buffer to decode
* @returns {TLV} TLV object
*/
function decodeBuffer(buffer) {
let position = 0;
let lastTag = -1;
const result = new Map();
if (!Buffer.isBuffer(buffer)) {
return result;
}
while (position < buffer.length) {
const tag = buffer.readUInt8(position++);
const length = buffer.readUInt8(position++);
const value = buffer.slice(position, position + length);
debug(`Read ${length} bytes for tag ${tag}: ${value.toString('hex')}`);
if (result.has(tag)) {
const existingValue = result.get(tag);
if (Array.isArray(existingValue) && tag === lastTag) {
const idx = existingValue.length - 1;
const newValue = Buffer.allocUnsafe(existingValue[idx].length + length);
existingValue[idx].copy(newValue, 0);
value.copy(newValue, existingValue[idx].length);
existingValue[idx] = newValue;
}
else if (Array.isArray(existingValue)) {
existingValue.push(value);
}
else if (tag === lastTag) {
const newValue = Buffer.allocUnsafe(existingValue.length + length);
existingValue.copy(newValue, 0);
value.copy(newValue, existingValue.length);
result.set(tag, newValue);
}
else {
result.set(tag, [existingValue, value]);
}
}
else {
result.set(tag, value);
}
position += length;
lastTag = tag;
}
return result;
}
/**
* Encode a TLV object into a buffer.
*
* See Chapter 12.1
*
* @param {TLV} obj - TLV object to encode
* @returns {Buffer} Encoded buffer
*/
function encodeObject(obj) {
const tlvs = [];
// eslint-disable-next-line prefer-const
for (let [tag, value] of obj) {
if (tag < 0 || tag > 255) {
continue;
}
if (tag === kTLVType_Separator) {
debug('Add separator to data');
tlvs.push(Buffer.from([kTLVType_Separator, 0]));
continue;
}
let values;
if (Array.isArray(value)) {
values = value;
}
else {
values = [value];
}
let valueIdx = 0;
while (valueIdx < values.length) {
let position = 0;
while (values[valueIdx].length - position > 0) {
const length = Math.min(values[valueIdx].length - position, 255);
debug(`Add ${length} bytes for tag ${tag}: ${values[valueIdx].toString('hex', position, position + length)}`);
const tlv = Buffer.allocUnsafe(length + 2);
tlv.writeUInt8(tag, 0);
tlv.writeUInt8(length, 1);
values[valueIdx].copy(tlv, 2, position, position + length);
tlvs.push(tlv);
position += length;
}
if (++valueIdx < values.length) {
debug('Add separator to data');
tlvs.push(Buffer.from([kTLVType_Separator, 0]));
}
}
}
return Buffer.concat(tlvs);
}
//# sourceMappingURL=tlv.js.map