Skip to content

Commit

Permalink
Make TLVs use maps internally. (#15)
Browse files Browse the repository at this point in the history
This preserves the order of keys when serializing, which is
required by certain devices.
  • Loading branch information
mrstegeman authored Feb 20, 2020
1 parent 0517d1a commit d711f46
Show file tree
Hide file tree
Showing 4 changed files with 269 additions and 237 deletions.
41 changes: 21 additions & 20 deletions lib/model/tlv.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ const kTLVType_Separator = 255;
* See Chapter 12.1
*
* @param {Buffer} buffer - Buffer to decode
* @returns {Object} TLV object
* @returns {Map} TLV object
*/
function decodeBuffer(buffer) {
let position = 0;
let lastTag = -1;
const result = {};
const result = new Map();

if (!Buffer.isBuffer(buffer)) {
return result;
Expand All @@ -27,25 +27,26 @@ function decodeBuffer(buffer) {
const length = buffer.readUInt8(position++);
const value = buffer.slice(position, position + length);

if (result.hasOwnProperty(tag)) {
if (Array.isArray(result[tag]) && tag === lastTag) {
const idx = result[tag].length - 1;
const newValue = Buffer.allocUnsafe(result[tag][idx].length + length);
result[tag][idx].copy(newValue, 0);
value.copy(newValue, result[tag][idx].length);
result[tag][idx] = newValue;
} else if (Array.isArray(result[tag])) {
result[tag].push(value);
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(result[tag].length + length);
result[tag].copy(newValue, 0);
value.copy(newValue, result[tag].length);
result[tag] = newValue;
const newValue = Buffer.allocUnsafe(existingValue.length + length);
existingValue.copy(newValue, 0);
value.copy(newValue, existingValue.length);
result.set(tag, newValue);
} else {
result[tag] = [result[tag], value];
result.set(tag, [existingValue, value]);
}
} else {
result[tag] = value;
result.set(tag, value);
}

position += length;
Expand All @@ -60,13 +61,14 @@ function decodeBuffer(buffer) {
*
* See Chapter 12.1
*
* @param {Object} object - TLV object to encode
* @param {Map} object - TLV object to encode
* @returns {Buffer} Encoded buffer
*/
function encodeObject(object) {
const tlvs = [];

for (let tag in object) {
// eslint-disable-next-line prefer-const
for (let [tag, value] of object) {
tag = parseInt(tag, 10);

if (tag < 0 || tag > 255) {
Expand All @@ -78,7 +80,6 @@ function encodeObject(object) {
continue;
}

const value = object[tag];
let values;
if (Array.isArray(value)) {
values = value;
Expand Down
Loading

2 comments on commit d711f46

@freaktechnik
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh wow, was this why the hue bridge wouldn't pair?

@mrstegeman
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. Hue is apparently super picky. The Python issue below was identical to ours.

jlusiardi/homekit_python#35

Please sign in to comment.