forked from mozilla/r2d2b2g
/
ctypes-bridge-builder.js
89 lines (76 loc) · 2.9 KB
/
ctypes-bridge-builder.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Bridge builder for ctypes
*
* where a bridge is defined as simply intercepting function calls from native code
* and re-firing them from a different library
*
*
* TODO: This code could (and probably should) be replaced by calling
* LoadLibrary properly in Windows native code
*/
'use strict';
;(function(exports) {
function BridgeBuilder(Instantiator, lib) {
this.I = Instantiator;
this.lib = lib;
this.saved_errno = -1;
}
BridgeBuilder.prototype = {
// returns [StructType, Struct, ref]
// where StructType is the type of the generated struct
// where Struct is the generated struct
// where ref is an array of functions used in function pointers (to prevent premature GC)
build: function build(name, bridge_funcs) {
bridge_funcs.forEach((function func(obj) {
for (let k in obj) {
this.I.declareFromFuncType(k, obj[k], this.lib);
}
}).bind(this));
const bridge_body = bridge_funcs.map(function func(obj) {
for (let k in obj) {
let o = {};
o[k] = obj[k].ptr;
return o;
}
return null; // to get rid of func not returning value warning
});
const struct_bridge =
new ctypes.StructType(name, bridge_body);
return [struct_bridge].concat(this._populate(struct_bridge(), bridge_body, bridge_funcs));
},
_zipWithIndex: function zipWithIndex(a) {
let i = 0;
return a.map(function(x) [x, i++]);
},
_populate: function populate(bridge, bridge_body, bridge_funcs) {
let ref = {};
this._zipWithIndex(bridge_body).forEach((function bridgeFunc([obj, i]) {
// grab the name of the function
for (let k in obj) {
// store the bridge to prevent premature garbage collection
ref[k] = (function bridgeCall() {
// get a reference to the actual DLL call
let f = this.I.use(k);
// call the real DLL function with the arguments to the bridge call
let res = f.apply(f, arguments);
this.saved_errno = ctypes.winLastError;
return res;
}).bind(this);
// install this callback in the bridge struct
bridge[k] = bridge_funcs[i][k].ptr(ref[k]);
}
return null; // to get rid of func not returning value warning
}).bind(this));
return [bridge, ref];
},
getLastError: function getLastError() {
return this.saved_errno;
}
};
exports.BridgeBuilder = BridgeBuilder;
}).apply(null,
typeof module !== 'undefined' ?
[exports] : [this]);