@homebridge/dbus-native 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +18 -0
- package/README.md +124 -0
- package/bin/dbus2js.js +118 -0
- package/index.js +155 -0
- package/lib/address-x11.js +38 -0
- package/lib/align.js +12 -0
- package/lib/bus.js +384 -0
- package/lib/constants.js +54 -0
- package/lib/dbus-buffer.js +182 -0
- package/lib/handshake.js +137 -0
- package/lib/header-signature.json +20 -0
- package/lib/hello-message.js +16 -0
- package/lib/introspect.js +201 -0
- package/lib/marshall.js +108 -0
- package/lib/marshallers.js +336 -0
- package/lib/message.js +118 -0
- package/lib/portforward.js +38 -0
- package/lib/readline.js +23 -0
- package/lib/server-handshake.js +37 -0
- package/lib/server.js +18 -0
- package/lib/signature.js +61 -0
- package/lib/stdifaces.js +203 -0
- package/lib/unmarshall.js +9 -0
- package/package.json +90 -0
package/lib/bus.js
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
const EventEmitter = require('events').EventEmitter;
|
|
2
|
+
const constants = require('./constants');
|
|
3
|
+
const stdDbusIfaces = require('./stdifaces');
|
|
4
|
+
const introspect = require('./introspect').introspectBus;
|
|
5
|
+
|
|
6
|
+
module.exports = function bus(conn, opts) {
|
|
7
|
+
if (!(this instanceof bus)) {
|
|
8
|
+
return new bus(conn);
|
|
9
|
+
}
|
|
10
|
+
if (!opts) opts = {};
|
|
11
|
+
|
|
12
|
+
var self = this;
|
|
13
|
+
this.connection = conn;
|
|
14
|
+
this.serial = 1;
|
|
15
|
+
this.cookies = {}; // TODO: rename to methodReturnHandlers
|
|
16
|
+
this.methodCallHandlers = {};
|
|
17
|
+
this.signals = new EventEmitter();
|
|
18
|
+
this.exportedObjects = {};
|
|
19
|
+
|
|
20
|
+
this.invoke = function(msg, callback) {
|
|
21
|
+
if (!msg.type) msg.type = constants.messageType.methodCall;
|
|
22
|
+
msg.serial = self.serial++;
|
|
23
|
+
this.cookies[msg.serial] = callback;
|
|
24
|
+
self.connection.message(msg);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
this.invokeDbus = function(msg, callback) {
|
|
28
|
+
if (!msg.path) msg.path = '/org/freedesktop/DBus';
|
|
29
|
+
if (!msg.destination) msg.destination = 'org.freedesktop.DBus';
|
|
30
|
+
if (!msg['interface']) msg['interface'] = 'org.freedesktop.DBus';
|
|
31
|
+
self.invoke(msg, callback);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
this.mangle = function(path, iface, member) {
|
|
35
|
+
var obj = {};
|
|
36
|
+
if (typeof path === 'object') {
|
|
37
|
+
// handle one argumant case mangle(msg)
|
|
38
|
+
obj.path = path.path;
|
|
39
|
+
obj['interface'] = path['interface'];
|
|
40
|
+
obj.member = path.member;
|
|
41
|
+
} else {
|
|
42
|
+
obj.path = path;
|
|
43
|
+
obj['interface'] = iface;
|
|
44
|
+
obj.member = member;
|
|
45
|
+
}
|
|
46
|
+
return JSON.stringify(obj);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
this.sendSignal = function(path, iface, name, signature, args) {
|
|
50
|
+
var signalMsg = {
|
|
51
|
+
type: constants.messageType.signal,
|
|
52
|
+
serial: self.serial++,
|
|
53
|
+
interface: iface,
|
|
54
|
+
path: path,
|
|
55
|
+
member: name
|
|
56
|
+
};
|
|
57
|
+
if (signature) {
|
|
58
|
+
signalMsg.signature = signature;
|
|
59
|
+
signalMsg.body = args;
|
|
60
|
+
}
|
|
61
|
+
self.connection.message(signalMsg);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// Warning: errorName must respect the same rules as interface names (must contain a dot)
|
|
65
|
+
this.sendError = function(msg, errorName, errorText) {
|
|
66
|
+
var reply = {
|
|
67
|
+
type: constants.messageType.error,
|
|
68
|
+
serial: self.serial++,
|
|
69
|
+
replySerial: msg.serial,
|
|
70
|
+
destination: msg.sender,
|
|
71
|
+
errorName: errorName,
|
|
72
|
+
signature: 's',
|
|
73
|
+
body: [errorText]
|
|
74
|
+
};
|
|
75
|
+
this.connection.message(reply);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
this.sendReply = function(msg, signature, body) {
|
|
79
|
+
var reply = {
|
|
80
|
+
type: constants.messageType.methodReturn,
|
|
81
|
+
serial: self.serial++,
|
|
82
|
+
replySerial: msg.serial,
|
|
83
|
+
destination: msg.sender,
|
|
84
|
+
signature: signature,
|
|
85
|
+
body: body
|
|
86
|
+
};
|
|
87
|
+
this.connection.message(reply);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// route reply/error
|
|
91
|
+
this.connection.on('message', function(msg) {
|
|
92
|
+
function invoke(impl, func, resultSignature) {
|
|
93
|
+
Promise.resolve()
|
|
94
|
+
.then(function() {
|
|
95
|
+
return func.apply(impl, (msg.body || []).concat(msg));
|
|
96
|
+
})
|
|
97
|
+
.then(
|
|
98
|
+
function(methodReturnResult) {
|
|
99
|
+
var methodReturnReply = {
|
|
100
|
+
type: constants.messageType.methodReturn,
|
|
101
|
+
serial: self.serial++,
|
|
102
|
+
destination: msg.sender,
|
|
103
|
+
replySerial: msg.serial
|
|
104
|
+
};
|
|
105
|
+
if (methodReturnResult !== null) {
|
|
106
|
+
methodReturnReply.signature = resultSignature;
|
|
107
|
+
methodReturnReply.body = [methodReturnResult];
|
|
108
|
+
}
|
|
109
|
+
self.connection.message(methodReturnReply);
|
|
110
|
+
},
|
|
111
|
+
function(e) {
|
|
112
|
+
self.sendError(
|
|
113
|
+
msg,
|
|
114
|
+
e.dbusName || 'org.freedesktop.DBus.Error.Failed',
|
|
115
|
+
e.message || ''
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
var handler;
|
|
122
|
+
if (
|
|
123
|
+
msg.type === constants.messageType.methodReturn ||
|
|
124
|
+
msg.type === constants.messageType.error
|
|
125
|
+
) {
|
|
126
|
+
handler = self.cookies[msg.replySerial];
|
|
127
|
+
if (handler) {
|
|
128
|
+
delete self.cookies[msg.replySerial];
|
|
129
|
+
var props = {
|
|
130
|
+
connection: self.connection,
|
|
131
|
+
bus: self,
|
|
132
|
+
message: msg,
|
|
133
|
+
signature: msg.signature
|
|
134
|
+
};
|
|
135
|
+
var args = msg.body || [];
|
|
136
|
+
if (msg.type === constants.messageType.methodReturn) {
|
|
137
|
+
args = [null].concat(args); // first argument - no errors, null
|
|
138
|
+
handler.apply(props, args); // body as array of arguments
|
|
139
|
+
} else {
|
|
140
|
+
handler.call(props, args); // body as first argument
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
} else if (msg.type === constants.messageType.signal) {
|
|
144
|
+
self.signals.emit(self.mangle(msg), msg.body, msg.signature);
|
|
145
|
+
} else {
|
|
146
|
+
// methodCall
|
|
147
|
+
|
|
148
|
+
if (stdDbusIfaces(msg, self)) return;
|
|
149
|
+
|
|
150
|
+
// exported interfaces handlers
|
|
151
|
+
var obj, iface, impl;
|
|
152
|
+
if ((obj = self.exportedObjects[msg.path])) {
|
|
153
|
+
if ((iface = obj[msg['interface']])) {
|
|
154
|
+
// now we are ready to serve msg.member
|
|
155
|
+
impl = iface[1];
|
|
156
|
+
var func = impl[msg.member];
|
|
157
|
+
if (!func) {
|
|
158
|
+
self.sendError(
|
|
159
|
+
msg,
|
|
160
|
+
'org.freedesktop.DBus.Error.UnknownMethod',
|
|
161
|
+
`Method "${msg.member}" on interface "${
|
|
162
|
+
msg.interface
|
|
163
|
+
}" doesn't exist`
|
|
164
|
+
);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
// TODO safety check here
|
|
168
|
+
var resultSignature = iface[0].methods[msg.member][1];
|
|
169
|
+
invoke(impl, func, resultSignature);
|
|
170
|
+
return;
|
|
171
|
+
} else {
|
|
172
|
+
console.error(`Interface ${msg['interface']} is not supported`);
|
|
173
|
+
// TODO: respond with standard dbus error
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// setMethodCall handlers
|
|
177
|
+
handler = self.methodCallHandlers[self.mangle(msg)];
|
|
178
|
+
if (handler) {
|
|
179
|
+
invoke(null, handler[0], handler[1]);
|
|
180
|
+
} else {
|
|
181
|
+
self.sendError(
|
|
182
|
+
msg,
|
|
183
|
+
'org.freedesktop.DBus.Error.UnknownService',
|
|
184
|
+
'Uh oh oh'
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
this.setMethodCallHandler = function(objectPath, iface, member, handler) {
|
|
191
|
+
var key = self.mangle(objectPath, iface, member);
|
|
192
|
+
self.methodCallHandlers[key] = handler;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
this.exportInterface = function(obj, path, iface) {
|
|
196
|
+
var entry;
|
|
197
|
+
if (!self.exportedObjects[path]) {
|
|
198
|
+
entry = self.exportedObjects[path] = {};
|
|
199
|
+
} else {
|
|
200
|
+
entry = self.exportedObjects[path];
|
|
201
|
+
}
|
|
202
|
+
entry[iface.name] = [iface, obj];
|
|
203
|
+
// monkey-patch obj.emit()
|
|
204
|
+
if (typeof obj.emit === 'function') {
|
|
205
|
+
var oldEmit = obj.emit;
|
|
206
|
+
obj.emit = function() {
|
|
207
|
+
var args = Array.prototype.slice.apply(arguments);
|
|
208
|
+
var signalName = args[0];
|
|
209
|
+
if (!signalName) throw new Error('Trying to emit undefined signa');
|
|
210
|
+
|
|
211
|
+
//send signal to bus
|
|
212
|
+
var signal;
|
|
213
|
+
if (iface.signals && iface.signals[signalName]) {
|
|
214
|
+
signal = iface.signals[signalName];
|
|
215
|
+
var signalMsg = {
|
|
216
|
+
type: constants.messageType.signal,
|
|
217
|
+
serial: self.serial++,
|
|
218
|
+
interface: iface.name,
|
|
219
|
+
path: path,
|
|
220
|
+
member: signalName
|
|
221
|
+
};
|
|
222
|
+
if (signal[0]) {
|
|
223
|
+
signalMsg.signature = signal[0];
|
|
224
|
+
signalMsg.body = args.slice(1);
|
|
225
|
+
}
|
|
226
|
+
self.connection.message(signalMsg);
|
|
227
|
+
self.serial++;
|
|
228
|
+
}
|
|
229
|
+
// note that local emit is likely to be called before signal arrives
|
|
230
|
+
// to remote subscriber
|
|
231
|
+
oldEmit.apply(obj, args);
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
// TODO: emit ObjectManager's InterfaceAdded
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
// register name
|
|
238
|
+
if (opts.direct !== true) {
|
|
239
|
+
this.invokeDbus({ member: 'Hello' }, function(err, name) {
|
|
240
|
+
if (err) throw new Error(err);
|
|
241
|
+
self.name = name;
|
|
242
|
+
});
|
|
243
|
+
} else {
|
|
244
|
+
self.name = null;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function DBusObject(name, service) {
|
|
248
|
+
this.name = name;
|
|
249
|
+
this.service = service;
|
|
250
|
+
this.as = function(name) {
|
|
251
|
+
return this.proxy[name];
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function DBusService(name, bus) {
|
|
256
|
+
this.name = name;
|
|
257
|
+
this.bus = bus;
|
|
258
|
+
this.getObject = function(name, callback) {
|
|
259
|
+
if (name === undefined)
|
|
260
|
+
return callback(new Error('Object name is null or undefined'));
|
|
261
|
+
var obj = new DBusObject(name, this);
|
|
262
|
+
introspect(obj, function(err, ifaces, nodes) {
|
|
263
|
+
if (err) return callback(err);
|
|
264
|
+
obj.proxy = ifaces;
|
|
265
|
+
obj.nodes = nodes;
|
|
266
|
+
callback(null, obj);
|
|
267
|
+
});
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
this.getInterface = function(objName, ifaceName, callback) {
|
|
271
|
+
this.getObject(objName, function(err, obj) {
|
|
272
|
+
if (err) return callback(err);
|
|
273
|
+
callback(null, obj.as(ifaceName));
|
|
274
|
+
});
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
this.getService = function(name) {
|
|
279
|
+
return new DBusService(name, this);
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
this.getObject = function(path, name, callback) {
|
|
283
|
+
var service = this.getService(path);
|
|
284
|
+
return service.getObject(name, callback);
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
this.getInterface = function(path, objname, name, callback) {
|
|
288
|
+
return this.getObject(path, objname, function(err, obj) {
|
|
289
|
+
if (err) return callback(err);
|
|
290
|
+
callback(null, obj.as(name));
|
|
291
|
+
});
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
// TODO: refactor
|
|
295
|
+
|
|
296
|
+
// bus meta functions
|
|
297
|
+
this.addMatch = function(match, callback) {
|
|
298
|
+
this.invokeDbus(
|
|
299
|
+
{ member: 'AddMatch', signature: 's', body: [match] },
|
|
300
|
+
callback
|
|
301
|
+
);
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
this.removeMatch = function(match, callback) {
|
|
305
|
+
this.invokeDbus(
|
|
306
|
+
{ member: 'RemoveMatch', signature: 's', body: [match] },
|
|
307
|
+
callback
|
|
308
|
+
);
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
this.getId = function(callback) {
|
|
312
|
+
this.invokeDbus({ member: 'GetId' }, callback);
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
this.requestName = function(name, flags, callback) {
|
|
316
|
+
this.invokeDbus(
|
|
317
|
+
{ member: 'RequestName', signature: 'su', body: [name, flags] },
|
|
318
|
+
function(err, name) {
|
|
319
|
+
if (callback) callback(err, name);
|
|
320
|
+
}
|
|
321
|
+
);
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
this.releaseName = function(name, callback) {
|
|
325
|
+
this.invokeDbus(
|
|
326
|
+
{ member: 'ReleaseName', signature: 's', body: [name] },
|
|
327
|
+
callback
|
|
328
|
+
);
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
this.listNames = function(callback) {
|
|
332
|
+
this.invokeDbus({ member: 'ListNames' }, callback);
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
this.listActivatableNames = function(callback) {
|
|
336
|
+
this.invokeDbus({ member: 'ListActivatableNames' }, callback);
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
this.updateActivationEnvironment = function(env, callback) {
|
|
340
|
+
this.invokeDbus(
|
|
341
|
+
{
|
|
342
|
+
member: 'UpdateActivationEnvironment',
|
|
343
|
+
signature: 'a{ss}',
|
|
344
|
+
body: [env]
|
|
345
|
+
},
|
|
346
|
+
callback
|
|
347
|
+
);
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
this.startServiceByName = function(name, flags, callback) {
|
|
351
|
+
this.invokeDbus(
|
|
352
|
+
{ member: 'StartServiceByName', signature: 'su', body: [name, flags] },
|
|
353
|
+
callback
|
|
354
|
+
);
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
this.getConnectionUnixUser = function(name, callback) {
|
|
358
|
+
this.invokeDbus(
|
|
359
|
+
{ member: 'GetConnectionUnixUser', signature: 's', body: [name] },
|
|
360
|
+
callback
|
|
361
|
+
);
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
this.getConnectionUnixProcessId = function(name, callback) {
|
|
365
|
+
this.invokeDbus(
|
|
366
|
+
{ member: 'GetConnectionUnixProcessID', signature: 's', body: [name] },
|
|
367
|
+
callback
|
|
368
|
+
);
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
this.getNameOwner = function(name, callback) {
|
|
372
|
+
this.invokeDbus(
|
|
373
|
+
{ member: 'GetNameOwner', signature: 's', body: [name] },
|
|
374
|
+
callback
|
|
375
|
+
);
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
this.nameHasOwner = function(name, callback) {
|
|
379
|
+
this.invokeDbus(
|
|
380
|
+
{ member: 'NameHasOwner', signature: 's', body: [name] },
|
|
381
|
+
callback
|
|
382
|
+
);
|
|
383
|
+
};
|
|
384
|
+
};
|
package/lib/constants.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
messageType: {
|
|
3
|
+
invalid: 0,
|
|
4
|
+
methodCall: 1,
|
|
5
|
+
methodReturn: 2,
|
|
6
|
+
error: 3,
|
|
7
|
+
signal: 4
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
headerTypeName: [
|
|
11
|
+
null,
|
|
12
|
+
'path',
|
|
13
|
+
'interface',
|
|
14
|
+
'member',
|
|
15
|
+
'errorName',
|
|
16
|
+
'replySerial',
|
|
17
|
+
'destination',
|
|
18
|
+
'sender',
|
|
19
|
+
'signature'
|
|
20
|
+
],
|
|
21
|
+
|
|
22
|
+
// TODO: merge to single hash? e.g path -> [1, 'o']
|
|
23
|
+
fieldSignature: {
|
|
24
|
+
path: 'o',
|
|
25
|
+
interface: 's',
|
|
26
|
+
member: 's',
|
|
27
|
+
errorName: 's',
|
|
28
|
+
replySerial: 'u',
|
|
29
|
+
destination: 's',
|
|
30
|
+
sender: 's',
|
|
31
|
+
signature: 'g'
|
|
32
|
+
},
|
|
33
|
+
headerTypeId: {
|
|
34
|
+
path: 1,
|
|
35
|
+
interface: 2,
|
|
36
|
+
member: 3,
|
|
37
|
+
errorName: 4,
|
|
38
|
+
replySerial: 5,
|
|
39
|
+
destination: 6,
|
|
40
|
+
sender: 7,
|
|
41
|
+
signature: 8
|
|
42
|
+
},
|
|
43
|
+
protocolVersion: 1,
|
|
44
|
+
flags: {
|
|
45
|
+
noReplyExpected: 1,
|
|
46
|
+
noAutoStart: 2
|
|
47
|
+
},
|
|
48
|
+
endianness: {
|
|
49
|
+
le: 108,
|
|
50
|
+
be: 66
|
|
51
|
+
},
|
|
52
|
+
messageSignature: 'yyyyuua(yv)',
|
|
53
|
+
defaultAuthMethods: ['EXTERNAL', 'DBUS_COOKIE_SHA1', 'ANONYMOUS']
|
|
54
|
+
};
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
const Long = require('long');
|
|
2
|
+
const parseSignature = require('./signature');
|
|
3
|
+
|
|
4
|
+
// Buffer + position + global start position ( used in alignment )
|
|
5
|
+
function DBusBuffer(buffer, startPos, options) {
|
|
6
|
+
if (typeof options !== 'object') {
|
|
7
|
+
options = { ayBuffer: true, ReturnLongjs: false };
|
|
8
|
+
} else if (options.ayBuffer === undefined) {
|
|
9
|
+
// default settings object
|
|
10
|
+
options.ayBuffer = true; // enforce truthy default props
|
|
11
|
+
}
|
|
12
|
+
this.options = options;
|
|
13
|
+
this.buffer = buffer;
|
|
14
|
+
(this.startPos = startPos ? startPos : 0), (this.pos = 0);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
DBusBuffer.prototype.align = function(power) {
|
|
18
|
+
var allbits = (1 << power) - 1;
|
|
19
|
+
var paddedOffset = ((this.pos + this.startPos + allbits) >> power) << power;
|
|
20
|
+
this.pos = paddedOffset - this.startPos;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
DBusBuffer.prototype.readInt8 = function() {
|
|
24
|
+
this.pos++;
|
|
25
|
+
return this.buffer[this.pos - 1];
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
DBusBuffer.prototype.readSInt16 = function() {
|
|
29
|
+
this.align(1);
|
|
30
|
+
var res = this.buffer.readInt16LE(this.pos);
|
|
31
|
+
this.pos += 2;
|
|
32
|
+
return res;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
DBusBuffer.prototype.readInt16 = function() {
|
|
36
|
+
this.align(1);
|
|
37
|
+
var res = this.buffer.readUInt16LE(this.pos);
|
|
38
|
+
this.pos += 2;
|
|
39
|
+
return res;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
DBusBuffer.prototype.readSInt32 = function() {
|
|
43
|
+
this.align(2);
|
|
44
|
+
var res = this.buffer.readInt32LE(this.pos);
|
|
45
|
+
this.pos += 4;
|
|
46
|
+
return res;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
DBusBuffer.prototype.readInt32 = function() {
|
|
50
|
+
this.align(2);
|
|
51
|
+
var res = this.buffer.readUInt32LE(this.pos);
|
|
52
|
+
this.pos += 4;
|
|
53
|
+
return res;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
DBusBuffer.prototype.readDouble = function() {
|
|
57
|
+
this.align(3);
|
|
58
|
+
var res = this.buffer.readDoubleLE(this.pos);
|
|
59
|
+
this.pos += 8;
|
|
60
|
+
return res;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
DBusBuffer.prototype.readString = function(len) {
|
|
64
|
+
if (len === 0) {
|
|
65
|
+
this.pos++;
|
|
66
|
+
return '';
|
|
67
|
+
}
|
|
68
|
+
var res = this.buffer.toString('utf8', this.pos, this.pos + len);
|
|
69
|
+
this.pos += len + 1; // dbus strings are always zero-terminated ('s' and 'g' types)
|
|
70
|
+
return res;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
DBusBuffer.prototype.readTree = function readTree(tree) {
|
|
74
|
+
switch (tree.type) {
|
|
75
|
+
case '(':
|
|
76
|
+
case '{':
|
|
77
|
+
case 'r':
|
|
78
|
+
this.align(3);
|
|
79
|
+
return this.readStruct(tree.child);
|
|
80
|
+
case 'a':
|
|
81
|
+
if (!tree.child || tree.child.length !== 1)
|
|
82
|
+
throw new Error('Incorrect array element signature');
|
|
83
|
+
var arrayBlobLength = this.readInt32();
|
|
84
|
+
return this.readArray(tree.child[0], arrayBlobLength);
|
|
85
|
+
case 'v':
|
|
86
|
+
return this.readVariant();
|
|
87
|
+
default:
|
|
88
|
+
return this.readSimpleType(tree.type);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
DBusBuffer.prototype.read = function read(signature) {
|
|
93
|
+
var tree = parseSignature(signature);
|
|
94
|
+
return this.readStruct(tree);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
DBusBuffer.prototype.readVariant = function readVariant() {
|
|
98
|
+
var signature = this.readSimpleType('g');
|
|
99
|
+
var tree = parseSignature(signature);
|
|
100
|
+
return [tree, this.readStruct(tree)];
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
DBusBuffer.prototype.readStruct = function readStruct(struct) {
|
|
104
|
+
var result = [];
|
|
105
|
+
for (var i = 0; i < struct.length; ++i) {
|
|
106
|
+
result.push(this.readTree(struct[i]));
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
DBusBuffer.prototype.readArray = function readArray(eleType, arrayBlobSize) {
|
|
112
|
+
var result;
|
|
113
|
+
var start = this.pos;
|
|
114
|
+
|
|
115
|
+
// special case: treat ay as Buffer
|
|
116
|
+
if (eleType.type === 'y' && this.options.ayBuffer) {
|
|
117
|
+
this.pos += arrayBlobSize;
|
|
118
|
+
return this.buffer.slice(start, this.pos);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// end of array is start of first element + array size
|
|
122
|
+
// we need to add 4 bytes if not on 8-byte boundary
|
|
123
|
+
// and array element needs 8 byte alignment
|
|
124
|
+
if (['x', 't', 'd', '{', '(', 'r'].indexOf(eleType.type) !== -1)
|
|
125
|
+
this.align(3);
|
|
126
|
+
var end = this.pos + arrayBlobSize;
|
|
127
|
+
result = [];
|
|
128
|
+
while (this.pos < end) result.push(this.readTree(eleType));
|
|
129
|
+
return result;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
DBusBuffer.prototype.readSimpleType = function readSimpleType(t) {
|
|
133
|
+
var data, len, word0, word1;
|
|
134
|
+
switch (t) {
|
|
135
|
+
case 'y':
|
|
136
|
+
return this.readInt8();
|
|
137
|
+
case 'b':
|
|
138
|
+
// TODO: spec says that true is strictly 1 and false is strictly 0
|
|
139
|
+
// shold we error (or warn?) when non 01 values?
|
|
140
|
+
return this.readInt32() ? true : false;
|
|
141
|
+
case 'n':
|
|
142
|
+
return this.readSInt16();
|
|
143
|
+
case 'q':
|
|
144
|
+
return this.readInt16();
|
|
145
|
+
case 'u':
|
|
146
|
+
return this.readInt32();
|
|
147
|
+
case 'i':
|
|
148
|
+
return this.readSInt32();
|
|
149
|
+
case 'g':
|
|
150
|
+
len = this.readInt8();
|
|
151
|
+
return this.readString(len);
|
|
152
|
+
case 's':
|
|
153
|
+
case 'o':
|
|
154
|
+
len = this.readInt32();
|
|
155
|
+
return this.readString(len);
|
|
156
|
+
// TODO: validate object path here
|
|
157
|
+
//if (t === 'o' && !isValidObjectPath(str))
|
|
158
|
+
// throw new Error('string is not a valid object path'));
|
|
159
|
+
case 'x':
|
|
160
|
+
//signed
|
|
161
|
+
this.align(3);
|
|
162
|
+
word0 = this.readInt32();
|
|
163
|
+
word1 = this.readInt32();
|
|
164
|
+
data = Long.fromBits(word0, word1, false);
|
|
165
|
+
if (this.options.ReturnLongjs) return data;
|
|
166
|
+
return data.toNumber(); // convert to number (good up to 53 bits)
|
|
167
|
+
case 't':
|
|
168
|
+
//unsigned
|
|
169
|
+
this.align(3);
|
|
170
|
+
word0 = this.readInt32();
|
|
171
|
+
word1 = this.readInt32();
|
|
172
|
+
data = Long.fromBits(word0, word1, true);
|
|
173
|
+
if (this.options.ReturnLongjs) return data;
|
|
174
|
+
return data.toNumber(); // convert to number (good up to 53 bits)
|
|
175
|
+
case 'd':
|
|
176
|
+
return this.readDouble();
|
|
177
|
+
default:
|
|
178
|
+
throw new Error(`Unsupported type: ${t}`);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
module.exports = DBusBuffer;
|