1 /* coded by Ketmar // Invisible Vector (psyc://ketmar.no-ip.org/~Ketmar)
2 * Understanding is not required. Only obedience.
4 * This program is free software. It comes without any warranty, to
5 * the extent permitted by applicable law. You can redistribute it
6 * and/or modify it under the terms of the Do What The Fuck You Want
7 * To Public License, Version 2, as published by Sam Hocevar. See
8 * http://www.wtfpl.net/txt/copying/ for more details.
10 ////////////////////////////////////////////////////////////////////////////////
11 // addonName: used in `alert()`
12 (function (addonName
, sandboxName
, urlMain
, urlJS
) {
13 const {utils
:Cu
, classes
:Cc
, interfaces
:Ci
, results
:Cr
} = Components
;
15 // bootstrapped addons has no `window`
16 const principal
= (typeof(window
) !== "undefined" ? window
: Cc
["@mozilla.org/systemprincipal;1"].createInstance(Ci
.nsIPrincipal
));
17 let gsbox
= new Cu
.Sandbox(principal
, {
18 sandboxName
: sandboxName
,
19 wantComponents
: false,
21 wantXHRConstructor
: true,
23 Cu
.import("resource://gre/modules/Services.jsm", gsbox
);
25 // bootstrapped addons has no `window`
26 if (typeof(window
) !== "undefined") {
27 gsbox
.window
= window
;
28 gsbox
.document
= window
.document
;
31 // add some common API
32 Object
.defineProperty(gsbox
, "isXPCShell", {get: function () false});
33 Object
.defineProperty(gsbox
, "contentURL", {get: function () urlMain
});
35 // `tieto` API: ties method to object, so it always has correct `this`
36 // you may specify additional arguments that will be always there
37 function tieto (obj
, method
) {
39 if (typeof(obj
) === "undefined") throw new Error("object or `null` expected");
40 if (obj
!== null && typeof(obj
) !== "object") throw new Error("object or `null` expected");
41 switch (typeof(method
)) {
43 if (!obj
) throw new Error("can't take method by name from `null` object");
44 if (!(method
in obj
)) throw new Error("method '"+method
+"' doesn't exist in object '"+obj
+"'");
46 if (typeof(mt
) !== "function") throw new Error("method '"+method
+"' isn't a function in object '"+obj
+"'");
53 throw new Error("`method` should be function or method name");
56 let rest
= Array
.prototype.splice
.call(arguments
, 2, arguments
.length
);
59 try { throw new Error("!"); } catch (e) {
60 //print("TIETO!\n"+e.stack);
61 stk = e.stack.split("\n")[1];
66 // `rest` is reused for each invocation, so copy it, and append new arguments to copy
67 let args
= Array
.prototype.slice
.call(rest
);
68 Array
.prototype.push
.apply(args
, arguments
);
69 return mt
.apply(me
, args
);
72 const sb_tieto
= tieto(gsbox
, tieto
);
73 Object
.defineProperty(gsbox
, "tieto", {get: function () sb_tieto
});
75 const sb_Components
= tieto(gsbox
, function (c
) c
, Components
);
76 const sb_Cu
= tieto(gsbox
, function (cu
) cu
, Cu
);
77 const sb_Cc
= tieto(gsbox
, function (cc
) cc
, Cc
);
78 const sb_Ci
= tieto(gsbox
, function (ci
) ci
, Ci
);
79 const sb_Cr
= tieto(gsbox
, function (cr
) cr
, Cr
);
81 Object
.defineProperty(gsbox
, "Components", {get: function () sb_Components()});
82 Object
.defineProperty(gsbox
, "Cu", {get: function () sb_Cu()});
83 Object
.defineProperty(gsbox
, "Cc", {get: function () sb_Cc()});
84 Object
.defineProperty(gsbox
, "Ci", {get: function () sb_Ci()});
85 Object
.defineProperty(gsbox
, "Cr", {get: function () sb_Cr()});
87 // console log functions
88 const oldlogerr
= (typeof(conlog
) == "function" ? logError
: null);
89 function logErr (str
) {
90 if (oldlogerr
) oldlogerr(str
); else Cu
.reportError(str
);
92 const sb_logError
= tieto(gsbox
, function (logErrMsg
) {
93 if (arguments
.length
) {
95 for (let idx
= 0; idx
< arguments
.length
; ++idx
) s
+= ""+arguments
[idx
];
99 Object
.defineProperty(gsbox
, "logError", {get: function () sb_logError
});
101 const sb_logException
= tieto(gsbox
, function (logErrMsg
) {
102 if (e
instanceof this.Error
) {
103 logErrMsg(""+msg
+" ERROR: "+e
.name
+": "+e
.message
+" : "+e
.lineNumber
)
104 if (e
.stack
) logErrMsg(e
.stack
);
110 Object
.defineProperty(gsbox
, "logException", {get: function () sb_logException
});
112 //let conlogEnabled = true;
113 //Object.defineProperty(gsbox, "conlogEnabled", {get: tieto(this, function () this.conlogEnabled)});
115 // https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsIConsoleService#logStringMessage() - wstring / wide string
116 const conService
= Cc
["@mozilla.org/consoleservice;1"].getService(Ci
.nsIConsoleService
);
117 const oldconlog
= (typeof(conlog
) == "function" ? conlog
: null);
118 function logStr (str
) {
119 if (oldconlog
) oldconlog(str
); else conService
.logStringMessage(str
);
122 const sb_conlog
= tieto(gsbox
, function (logStrMsg
) {
123 if (arguments
.length
> 1) {
124 let le
= ("guerillaOptions" in this ? this["guerillaOptions"].logEnabled
: true);
127 for (let idx
= 1; idx
< arguments
.length
; ++idx
) s
+= ""+arguments
[idx
];
131 Object
.defineProperty(gsbox
, "conlog", {get: function () sb_conlog
});
133 const sb_print
= tieto(gsbox
, function (logStrMsg
) {
134 if (arguments
.length
> 1) {
135 let le
= ("guerillaOptions" in this ? this["guerillaOptions"].logEnabled
: true);
138 let wasPrint
= false;
139 for (let idx
= 1; idx
< arguments
.length
; ++idx
) {
140 let t
= ""+arguments
[idx
];
143 logStrMsg(s
.substr(1));
146 Object
.defineProperty(gsbox
, "print", {get: function () sb_print
});
149 const newURI
= Cc
["@mozilla.org/network/io-service;1"].getService(Ci
.nsIIOService
).newURI
;
150 //const newFileURI = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService).newFileURI;
151 const loadSubScript
= Cc
["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci
.mozIJSSubScriptLoader
).loadSubScript
;
153 // include("incname")
154 const sb_include
= tieto(gsbox
, function (scriptSpec
, newURI
, loadSubScript
, reportError
, name
) {
155 if (name
.length
== 0) throw new Error("invalid include name: '"+name
+"'");
156 if (!(/.\.js$/.test(name
))) name
+= ".js";
157 let fullURL
= (/^(?:chrome|resource):/.test(name
) ? name
: scriptSpec
+name
); // hack
158 //reportError("including '"+name+"' : ["+fullURL+"]");
160 let uri
= newURI(fullURL
, null, null);
161 loadSubScript(uri
.spec
, gsbox
, "UTF-8");
163 reportError("INCLUDE ERROR: "+e
.name
+": "+e
.message
+" : "+e
.lineNumber
+"\n"+e
.stack
);
167 }, urlJS
+"includes/", newURI
, loadSubScript
, Cu
.reportError
);
168 Object
.defineProperty(gsbox
, "include", {get: function () sb_include
});
171 let modules
= {}; // list of loaded modules
173 // require("modname")
174 const sb_require
= tieto(gsbox
, function (scriptSpec
, newURI
, loadSubScript
, reportError
, import_
, modules
, name
) {
175 if (name
.length
== 0) throw new Error("invalid include name: '"+name
+"'");
176 if (!(/.\.js$/.test(name
))) name
+= ".js";
177 if (name
in modules
) return modules
[name
];
178 let fullURL
= (/^(?:chrome|resource):/.test(name
) ? name
: scriptSpec
+name
); // hack
179 //reportError("requiring '"+name+"' : ["+fullURL+"]");
181 let scope
= Object
.create(gsbox
);
182 // uses(name[, name]...);
183 let sc_uses
= tieto(gsbox
, function (scope
, import_
) {
184 if (arguments
.length
> 3) {
185 for (let idx
= 2; idx
< arguments
.length
; ++idx
) import_(arguments
[idx
], scope
);
187 } else if (arguments
.length
== 3) {
188 return import_(arguments
[2], scope
);
191 Object
.defineProperty(scope
, "uses", {get: function () sc_uses
});
193 scope
.exportsGlobal
= {};
195 for (let k in gsbox) {
197 if (k !== "__exposedProps__" && !(k in scope) && Object.prototype.hasOwnProperty.call(gsbox, k)) {
198 print(" EXPORT: k=["+k+"]");
199 try { scope[k] = gsbox[k]; } catch (e) {}
204 let uri
= newURI(fullURL
, null, null);
205 loadSubScript(uri
.spec
, scope
, "UTF-8");
207 reportError("REQUIRE ERROR: "+e
.name
+": "+e
.message
+" : "+e
.lineNumber
+"\n"+e
.stack
);
211 modules
[name
] = scope
.exports
;
212 if (typeof(scope
.exportsGlobal
) === "object") {
213 for (let k
in scope
.exportsGlobal
) {
214 if (k
!== "__exposedProps__" && Object
.prototype.hasOwnProperty
.call(scope
.exportsGlobal
, k
)) {
215 try { gsbox
[k
] = scope
.exportsGlobal
[k
]; } catch (e
) {}
219 return scope
.exports
;
220 }, urlJS
+"modules/", newURI
, loadSubScript
, Cu
.reportError
, Cu
.import, modules
);
221 Object
.defineProperty(gsbox
, "require", {get: function () sb_require
});
224 const promptSvc
= Cc
["@mozilla.org/embedcomp/prompt-service;1"].getService(Ci
.nsIPromptService
);
226 const sb_alert
= tieto(gsbox
, function (promptSvc
, addonName
, msg
) {
227 promptSvc
.alert(null, addonName
, ""+msg
);
228 }, promptSvc
, addonName
);
229 Object
.defineProperty(gsbox
, "alert", {get: function () sb_alert
});
232 let startupHooks
= [], shutdownHooks
= [];
234 function runHooks (list
, rev
) {
235 let rest
= Array
.prototype.splice
.call(arguments
, 2, arguments
.length
);
236 // hack: if (rev === false): this is "onStartup"
238 // now load main file
239 gsbox
.include(urlJS
+"main.js");
241 let idx
= (rev
? list
.length
: -1);
244 if (--idx
< 0) break;
246 if (++idx
>= list
.length
) break;
250 //conService.logStringMessage("running hook: '"+h.name+"'");
251 let args
= Array
.prototype.slice
.call(rest
);
252 //Array.prototype.push.apply(args, arguments);
253 h
.cback
.apply(gsbox
, args
);
255 Cu
.reportError("HOOK ERROR: "+e
.name
+": "+e
.message
+" : "+e
.lineNumber
+"\n"+e
.stack
);
261 function addHook (hooks
, name
, cback
) {
262 if (typeof(cback
) === "undefined") {
263 // register*Hook(hookfn)
267 if (typeof(name
) === "undefined") throw new Error("name or `null` expected");
268 if (!name
) name
= "";
269 if (typeof(name
) !== "string") throw new Error("name or `null` expected");
270 if (typeof(cback
) !== "function") throw new Error("function expected");
271 hooks
.push({name
:name
, cback
:cback
});
274 const sb_rsth
= tieto(gsbox
, addHook
, startupHooks
);
275 const sb_rsuh
= tieto(gsbox
, addHook
, shutdownHooks
);
277 // registerStartupHook(name, hookfn)
278 Object
.defineProperty(gsbox
, "registerStartupHook", {get: function () sb_rsth
});
279 // registerShutdownHook(name, hookfn)
280 Object
.defineProperty(gsbox
, "registerShutdownHook", {get: function () sb_rsuh
});
285 defProp
: tieto(this, function (mainobj
, name
, ops
) {
286 //Cu.reportError("GS: defining property '"+name+"'");
287 mainobj
.defineProperty(gsbox
, name
, ops
);
289 onInstall: function () {},
290 onUnistall: function () {},
291 onStartup
: tieto(this, runHooks
, startupHooks
, false),
292 onShutdown
: tieto(this, runHooks
, shutdownHooks
, true),