Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ node_js:
- 4.2
- 6
- 8
- 10
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ options:
- busAddress - encoded bus address. Default is `DBUS_SESSION_BUS_ADDRESS` environment variable. See http://dbus.freedesktop.org/doc/dbus-specification.html#addresses
- authMethods - array of authentication methods, which are attempted in the order provided (default:['EXTERNAL', 'DBUS_COOKIE_SHA1', 'ANONYMOUS'])
- ayBuffer - boolean (default:true): if true 'ay' dbus fields are returned as buffers
- ReturnLongjs - boolean (default:false): if true 64 bit dbus fields (x/t) are read out as Long.js objects, otherwise they are converted to numbers (which should be good up to 53 bits)
- ReturnLongjs - boolean (default:false): **DEPRECATED** See returnType64.
- returnType64 - string (default:'number'): Sets the return type for unmarshalling 64 bit fields (x/t). Options are: 'number', 'bigint', 'longjs'.
- ( TODO: add/document option to use adress from X11 session )

connection has only one method, `message(msg)`
Expand Down Expand Up @@ -102,10 +103,12 @@ conn.on('message', function(msg) { console.log(msg); });
Long.js is used for 64 Bit support. https://github.com/dcodeIO/long.js
The following javascript types can be marshalled into 64 bit dbus fields:
- typeof 'number' up to 53bits
- typeof 'bigint' (if available)
- typeof 'string' (consisting of decimal digits with no separators or '0x' prefixed hexadecimal) up to full 64bit range
- Long.js objects (or object with compatible properties)

By default 64 bit dbus fields are unmarshalled into a 'number' (with precision loss beyond 53 bits). Use {ReturnLongjs:true} option to return the actual Long.js object and preserve the entire 64 bits.
By default 64 bit dbus fields are unmarshalled into a 'number' with precision loss beyond 53 bits.
To preserve all 64 bits: If BigInt is available, you can use the option {returnType64:'bigint'}. Otherwise you can use {returnType64:'longjs'}.

### Links
- http://cgit.freedesktop.org/dbus - freedesktop reference C library
Expand Down
3 changes: 2 additions & 1 deletion lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,6 @@ module.exports = {
be: 66
},
messageSignature: 'yyyyuua(yv)',
defaultAuthMethods: ['EXTERNAL', 'DBUS_COOKIE_SHA1', 'ANONYMOUS']
defaultAuthMethods: ['EXTERNAL', 'DBUS_COOKIE_SHA1', 'ANONYMOUS'],
types64: { number: 'number', bigint: 'bigint', longjs: 'longjs' },
};
22 changes: 18 additions & 4 deletions lib/dbus-buffer.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const Long = require('long');
const parseSignature = require('./signature');
const constants = require('./constants');

// Buffer + position + global start position ( used in alignment )
function DBusBuffer(buffer, startPos, options) {
Expand Down Expand Up @@ -129,6 +130,21 @@ DBusBuffer.prototype.readArray = function readArray(eleType, arrayBlobSize) {
return result;
};

// Take a Long.js object and return a number (or BigInt if needed and available)
function convertLong(data, opt) {
if (opt.ReturnLongjs) return data; // deprecated option check
switch (opt.returnType64) {
case constants.types64.longjs:
return data;
case constants.types64.bigint:
if (typeof BigInt !== 'function') throw new Error('BigInt not available, check runtime version!');
return BigInt(data.toString()); // is there efficient way to pop BigInt from two 32bit 'digits' ? Do the math?
case constants.types64.number:
default:
return data.toNumber();
}
}

DBusBuffer.prototype.readSimpleType = function readSimpleType(t) {
var data, len, word0, word1;
switch (t) {
Expand Down Expand Up @@ -162,16 +178,14 @@ DBusBuffer.prototype.readSimpleType = function readSimpleType(t) {
word0 = this.readInt32();
word1 = this.readInt32();
data = Long.fromBits(word0, word1, false);
if (this.options.ReturnLongjs) return data;
return data.toNumber(); // convert to number (good up to 53 bits)
return convertLong(data, this.options);
case 't':
//unsigned
this.align(3);
word0 = this.readInt32();
word1 = this.readInt32();
data = Long.fromBits(word0, word1, true);
if (this.options.ReturnLongjs) return data;
return data.toNumber(); // convert to number (good up to 53 bits)
return convertLong(data, this.options);
case 'd':
return this.readDouble();
default:
Expand Down
7 changes: 3 additions & 4 deletions lib/marshallers.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ var MakeSimpleMarshaller = function(signature) {
// utf8 string
align(ps, 4);
const buff = Buffer.from(data, 'utf8');
ps
.word32le(buff.length)
ps.word32le(buff.length)
.put(buff)
.word8(0);
ps._offset += 5 + buff.length;
Expand All @@ -80,8 +79,7 @@ var MakeSimpleMarshaller = function(signature) {
this.check(data);
// signature
const buff = Buffer.from(data, 'ascii');
ps
.word8(data.length)
ps.word8(data.length)
.put(buff)
.word8(0);
ps._offset += 2 + buff.length;
Expand Down Expand Up @@ -248,6 +246,7 @@ var checkBoolean = function(data) {
var makeLong = function(val, signed) {
if (val instanceof Long) return val;
if (val instanceof Number) val = val.valueOf();
if (typeof val === 'bigint') val = val.toString(); // is there a way to efficiently get the two 32bit 'digits' out of BigInt? Do the math?
if (typeof val === 'number') {
try {
// Long.js won't alert you to precision loss in passing more than 53 bit ints through a double number, so we check here
Expand Down
74 changes: 58 additions & 16 deletions test/unmarshall-basic.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const marshall = require('../lib/marshall');
const unmarshall = require('../lib/unmarshall');
const assert = require('assert');
const Long = require('long');
const constants = require('../lib/constants');

var LongMaxS64 = Long.fromString('9223372036854775807', false);
var LongMinS64 = Long.fromString('-9223372036854775808', false);
Expand Down Expand Up @@ -202,7 +203,7 @@ describe('marshall/unmarshall', function() {
['0x7FFFFFFFFFFFFFFF'],
false,
[LongMaxS64],
{ ReturnLongjs: true }
{ returnType64: constants.types64.longjs }
],
['t', ['0x1FFFFFFFFFFFFF'], false, [9007199254740991]],
['t', ['0x0000'], false, [0]],
Expand All @@ -211,42 +212,42 @@ describe('marshall/unmarshall', function() {
['0xFFFFFFFFFFFFFFFF'],
false,
[LongMaxU64],
{ ReturnLongjs: true }
{ returnType64: constants.types64.longjs }
],
['x', [LongMaxS53], false, [9007199254740991]], // make sure Longjs objects convert to 53bit numbers
['x', [LongMinS53], false, [-9007199254740991]],
['t', [LongMaxU53], false, [9007199254740991]],
['t', [LongMinU53], false, [0]],
['x', [9007199254740991], false, [LongMaxS53], { ReturnLongjs: true }], // 53bit numbers to objects
['x', [-9007199254740991], false, [LongMinS53], { ReturnLongjs: true }],
['t', [9007199254740991], false, [LongMaxU53], { ReturnLongjs: true }],
['t', [0], false, [LongMinU53], { ReturnLongjs: true }],
['x', [9007199254740991], false, [LongMaxS53], { returnType64: constants.types64.longjs }], // 53bit numbers to objects
['x', [-9007199254740991], false, [LongMinS53], { returnType64: constants.types64.longjs }],
['t', [9007199254740991], false, [LongMaxU53], { returnType64: constants.types64.longjs }],
['t', [0], false, [LongMinU53], { returnType64: constants.types64.longjs }],
[
'x',
['9223372036854775807'],
false,
[LongMaxS64],
{ ReturnLongjs: true }
{ returnType64: constants.types64.longjs }
], // strings to objects
[
'x',
['-9223372036854775808'],
false,
[LongMinS64],
{ ReturnLongjs: true }
{ returnType64: constants.types64.longjs }
],
[
't',
['18446744073709551615'],
false,
[LongMaxU64],
{ ReturnLongjs: true }
{ returnType64: constants.types64.longjs }
],
['t', ['0'], false, [LongMinU64], { ReturnLongjs: true }],
['x', [LongMaxS64], false, [LongMaxS64], { ReturnLongjs: true }], // Longjs object to objects
['x', [LongMinS64], false, [LongMinS64], { ReturnLongjs: true }],
['t', [LongMaxU64], false, [LongMaxU64], { ReturnLongjs: true }],
['t', [LongMinU64], false, [LongMinU64], { ReturnLongjs: true }],
['t', ['0'], false, [LongMinU64], { returnType64: constants.types64.longjs }],
['x', [LongMaxS64], false, [LongMaxS64], { returnType64: constants.types64.longjs }], // Longjs object to objects
['x', [LongMinS64], false, [LongMinS64], { returnType64: constants.types64.longjs }],
['t', [LongMaxU64], false, [LongMaxU64], { returnType64: constants.types64.longjs }],
['t', [LongMinU64], false, [LongMinU64], { returnType64: constants.types64.longjs }],
[
'x',
[
Expand All @@ -258,7 +259,7 @@ describe('marshall/unmarshall', function() {
],
false,
[LongMaxS64],
{ ReturnLongjs: true }
{ returnType64: constants.types64.longjs }
], // non-instance Longjs object to objects
[
'x',
Expand All @@ -283,7 +284,7 @@ describe('marshall/unmarshall', function() {
],
false,
[LongMaxU64],
{ ReturnLongjs: true }
{ returnType64: constants.types64.longjs }
],
[
't',
Expand Down Expand Up @@ -346,6 +347,47 @@ describe('marshall/unmarshall', function() {
]
};

// If BigInt is supported, test it.
if (typeof BigInt === 'function') {
// BigInt presently has issue with JSON.stringify, so check for a toJSON() override for our testing manifold
if (typeof BigInt.prototype.toJSON !== 'function')
BigInt.prototype.toJSON = function() {
return this.toString();
};
// Check the extremes
var BigIntMaxS64 = BigInt('9223372036854775807');
var BigIntMinS64 = BigInt('-9223372036854775808');
var BigIntMaxU64 = BigInt('18446744073709551615');
tests['BigInt support'] = [
// Returning Long.js
[
'x',
[BigIntMaxS64],
false,
[LongMaxS64],
{ returnType64: constants.types64.longjs }
],
[
'x',
[BigIntMinS64],
false,
[LongMinS64],
{ returnType64: constants.types64.longjs }
],
[
't',
[BigIntMaxU64],
false,
[LongMaxU64],
{ returnType64: constants.types64.longjs }
],
// Returning BigInt
['x', [BigIntMaxS64], false, [BigIntMaxS64], { returnType64: constants.types64.bigint }],
['x', [BigIntMinS64], false, [BigIntMinS64], { returnType64: constants.types64.bigint }],
['t', [BigIntMaxU64], false, [BigIntMaxU64], { returnType64: constants.types64.bigint }],
];
}

var testName, testData, testNum;
for (testName in tests) {
for (testNum = 0; testNum < tests[testName].length; ++testNum) {
Expand Down