h0x0d

Windows 10 11082 CONTENTSCRIPT.JS

Dec 17th, 2015
319
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2. (function (nativeMsContentScript) {
  3.     var nativeJSON = window.JSON;
  4.  
  5.     // Synchronous function are from syncmethodhandler.h. They should be kept in alphabetical order.
  6.     const functionId_getIsInPrivate = 2;
  7.     const functionId_getMessage = 3;
  8.     const functionId_getUILanguage = 4;
  9.     const functionId_permissionsCheckInternal = 5;
  10.  
  11.     // These values should never be touched.
  12.     const componentId_extensionTrident = 1;
  13.     const componentId_manager = 4;
  14.  
  15.     // These values are pulled from bhxmessages.h. You may notice they are in alphabetical order (hint, hint).
  16.     // During the routing, the starting enumeration value is added/subtracted for outgoing/incoming messages
  17.     // respectively, so the id values here should be the offsets.
  18.  
  19.     // Bhx::Data::ExtensionManager::EventId
  20.     const eventId_storageOnChanged = 8;
  21.  
  22.     // Bhx::Message::ExtensionManager
  23.     const functionId_notifyEventListener = 10;
  24.     const functionId_storageLocalGet = 17;
  25.     const functionId_storageLocalRemove = 24;
  26.     const functionId_storageLocalSet = 18;
  27.  
  28.     // Permission values.
  29.     const permissionId_storage = 14;
  30.  
  31.     // API used constants
  32.     const i18n_maxAllowedSubstitutions = 9;
  33.  
  34.     var storedHandlers = [];
  35.     var storedCallbacks = [];
  36.     var nextCallback = 0;
  37.  
  38.     Object.defineProperty(window, "msBrowser", {
  39.         get: delayInitMsBrowser,
  40.         configurable: true,
  41.         enumerable: true
  42.     });
  43.  
  44.     function delayInitMsBrowser() {
  45.         var wrapMsBrowser = Object.defineProperties({}, {
  46.             "extension": {
  47.                 get: delayInitExtension,
  48.                 configurable: true,
  49.                 enumerable: true
  50.             },
  51.             "i18n": {
  52.                 get: delayInitI18n,
  53.                 configurable: true,
  54.                 enumerable: true
  55.             },
  56.             "runtime": {
  57.                 get: delayInitRuntime,
  58.                 configurable: true,
  59.                 enumerable: true
  60.             },
  61.             "storage": {
  62.                 get: delayInitStorage,
  63.                 configurable: true,
  64.                 enumerable: true
  65.             }
  66.         });
  67.  
  68.         // Replace delayInit with the initialized object to avoid repeated calls to delayInit.
  69.         Object.defineProperty(window, "msBrowser", {
  70.             value: wrapMsBrowser,
  71.             configurable: true,
  72.             enumerable: true
  73.         });
  74.         return wrapMsBrowser;
  75.     }
  76.  
  77.     function delayInitExtension() {
  78.         var wrapExtension = Object.defineProperties({}, {
  79.             "inPrivateContext": {
  80.                 get: extension_inPrivateContext_indirect,
  81.                 configurable: true,
  82.                 enumerable: true
  83.             }
  84.         });
  85.  
  86.         function extension_inPrivateContext_indirect() {
  87.             var isInPrivate = false;
  88.             var undef;
  89.             var syncValue = ExecuteGenericSynchronousFunction(functionId_getIsInPrivate, undef);
  90.             if (typeof(syncValue) == "boolean") {
  91.                 isInPrivate = syncValue;
  92.             }
  93.  
  94.             return isInPrivate;
  95.         }
  96.  
  97.         // Replace delayInit with the initialized object to avoid repeated calls to delayInit.
  98.         Object.defineProperty(window.msBrowser, "extension", {
  99.             value: wrapExtension,
  100.             configurable: true,
  101.             enumerable: true
  102.         });
  103.  
  104.         return wrapExtension;
  105.     }
  106.  
  107.     function delayInitI18n() {
  108.         var wrapI18n = Object.defineProperties({}, {
  109.             "getUILanguage": {
  110.                 get: i18n_getUILanguage_indirect,
  111.                 configurable: true,
  112.                 enumerable: true
  113.             },
  114.             "getMessage": {
  115.                 value: i18n_getMessage_indirect,
  116.                 configurable: true,
  117.                 enumerable: true
  118.             }
  119.         });
  120.  
  121.         function i18n_getUILanguage_indirect() {
  122.             var UILanguage = "";
  123.             var undef;
  124.             var syncValue = ExecuteGenericSynchronousFunction(functionId_getUILanguage, undef);
  125.             if (typeof (syncValue) == "string") {
  126.                 UILanguage = syncValue;
  127.             }
  128.  
  129.             return UILanguage;
  130.         }
  131.  
  132.         function i18n_getMessage_indirect() {
  133.             var expectedArguments = [
  134.             { type: "string", name: "messageName" },
  135.             { type: "string or array", name: "substitutions", optional: true }];
  136.             TestParameterTypes("i18n.getMessage", arguments, expectedArguments);
  137.  
  138.             var message = null;
  139.             var messageName = null;
  140.             var substCount = 0; // 0 if there's no substring
  141.             if (arguments.length == 2) {
  142.                 if (GetTypeName(arguments[1]) === "array") {
  143.                     substCount = arguments[1].length;
  144.                     if (substCount > i18n_maxAllowedSubstitutions) {
  145.                         throw "Error: Substitution strings exceed maximum allowance";
  146.                     }
  147.                     for (var i = 0; i < substCount; i++) {
  148.                         if (typeof (arguments[0][i]) !== "string") {
  149.                             throw "Error: Invalid value for argument 1. All items in the array must be strings.";
  150.                         }
  151.                     }
  152.                 }
  153.                 else if (GetTypeName(arguments[1]) === "string") {
  154.                     substCount = 1;
  155.                 }
  156.             }
  157.             var parameters = {};
  158.             parameters.messageName = arguments[0];
  159.             parameters.substCount = substCount;
  160.             parameters.substitutions = (substCount > 0) ? arguments[1] : null;
  161.  
  162.             var messageValue = ExecuteGenericSynchronousFunction(functionId_getMessage, parameters);
  163.             if (typeof (messageValue) == "string") {
  164.                 message = messageValue;
  165.             }
  166.  
  167.             return message;
  168.         };
  169.  
  170.         // Replace delayInit with the initialized object to avoid repeated calls to delayInit.
  171.         Object.defineProperty(window.msBrowser, "i18n", {
  172.             value: wrapI18n,
  173.             configurable: true,
  174.             enumerable: true
  175.         });
  176.  
  177.         return wrapI18n;
  178.     }
  179.  
  180.     function delayInitRuntime() {
  181.         var wrapRuntime = Object.defineProperties({}, {
  182.             "getURL": {
  183.                 value: getUrlIndirect.bind(nativeMsContentScript),
  184.                 configurable: true,
  185.                 enumerable: true
  186.             },
  187.             "sendMessage": {
  188.                 value: sendMessageIndirect.bind(nativeMsContentScript),
  189.                 configurable: true,
  190.                 enumerable: true
  191.             },
  192.             "onMessage": {
  193.                 get: delayInitOnMessage,
  194.                 configurable: true,
  195.                 enumerable: true
  196.             }
  197.         });
  198.  
  199.         function getUrlIndirect(resource) {
  200.             var extensionId = this.getExtensionId();
  201.             var url = "ms-browser-extension://" + extensionId;
  202.  
  203.             if(resource.substr(0, 1) !== "/")
  204.                 url += "/";
  205.  
  206.             url += resource;
  207.  
  208.             return url;
  209.         }
  210.  
  211.         function callbackIndirect(callback) {
  212.             return function () {
  213.                 var args = nativeJSON.parse(arguments[0]);
  214.                 var result = {};
  215.                 function sendResponse(response) {
  216.                     result.response = nativeJSON.stringify(response);
  217.                 }
  218.                 var msg = nativeJSON.parse(args.msg);
  219.                 result.async = callback.call(this, msg, args.sender, sendResponse.bind(window)) ? true : false;
  220.                 return result;
  221.                 // Need to handle sending the response async - http://osgvsowi/674353
  222.             }
  223.         }
  224.  
  225.         function delayInitOnMessage() {
  226.             var wrapOnMessage = Object.defineProperties({}, {
  227.                 "addListener": {
  228.                     value: function(callback) { nativeMsContentScript.addEventListener("message", callbackIndirect(callback)); },
  229.                     configurable: true,
  230.                     enumerable: true
  231.                 }
  232.             });
  233.  
  234.             // Replace delayInit with the initialized object to avoid repeated calls to delayInit.
  235.             Object.defineProperty(window.msBrowser.runtime, "onMessage", {
  236.                 value: wrapOnMessage,
  237.                 configurable: true,
  238.                 enumerable: true
  239.             });
  240.             return wrapOnMessage;
  241.         }
  242.  
  243.         function delayInitOnMessageExternal() {
  244.             var wrapOnMessageExternal = Object.defineProperties({}, {
  245.                 "addListener": {
  246.                     value: function(callback) { nativeMsContentScript.addEventListener("externalMessage", callbackIndirect(callback)); },
  247.                     configurable: true,
  248.                     enumerable: true
  249.                 }
  250.             });
  251.  
  252.             // Replace delayInit with the initialized object to avoid repeated calls to delayInit.
  253.             Object.defineProperty(window.msBrowser.runtime, "onMessageExternal", {
  254.                 value: wrapOnMessageExternal,
  255.                 configurable: true,
  256.                 enumerable: true
  257.             });
  258.             return wrapOnMessageExternal;
  259.         }
  260.  
  261.         function sendMessageIndirect(/* optional string extensionId, any message, optional object options, optional function responseCallback */) {
  262.  
  263.             if (arguments.length < 1) {
  264.                 return null;
  265.             }
  266.  
  267.             var index = arguments.length - 1;
  268.  
  269.             var responseCallback = null;
  270.             if (typeof arguments[index] === "function") {
  271.                 responseCallback = arguments[index];
  272.                 --index;
  273.             }
  274.  
  275.             var options = null;
  276.             if (index >= 2) {
  277.                 // More than two arguments remain so options param must  present.
  278.                 options = arguments[index];
  279.                 --index;
  280.             }
  281.             else if (index === 2) {
  282.                 // The logic: assume that the first param is the optional extension id if it is present and is a string, hence no options argument in this case.
  283.                 if (!(arguments[0] === null || typeof arguments[0] === "string")) {
  284.                     options = arguments[index];
  285.                     --index;
  286.                 }
  287.             }
  288.  
  289.             var message = arguments[index]; // Must be present.
  290.             --index;
  291.  
  292.             var extensionId = null;
  293.             if (index >= 0) {
  294.                 extensionId = arguments[index];
  295.                 --index;
  296.             }
  297.  
  298.             if (index !== -1) {
  299.                 // Requires exact number of arguments, no extra arguments allowed.
  300.                 return null;
  301.             } else {
  302.                 // Always stringify on sendMessage side and always parse on the callback side.
  303.                 // Otherwise, callback cannot distinuish between a message sending an object and another message sending its string equivalent.
  304.                 if (extensionId !== null) {
  305.                     return this.postExternalMessage(extensionId, nativeJSON.stringify(message), responseCallback);
  306.                 } else {
  307.                     return this.postMessage(nativeJSON.stringify(message), responseCallback);
  308.                 }
  309.             }
  310.         };
  311.  
  312.         // Replace delayInit with the initialized object to avoid repeated calls to delayInit.
  313.         Object.defineProperty(window.msBrowser, "runtime", {
  314.             value: wrapRuntime,
  315.             configurable: true,
  316.             enumerable: true
  317.         });
  318.         return wrapRuntime;
  319.     }
  320.    
  321.     function delayInitStorage() {
  322.         var wrapStorage;
  323.         var hasPermission = ExecuteGenericSynchronousFunction(functionId_permissionsCheckInternal, permissionId_storage);
  324.         if (typeof(hasPermission) == "boolean" && hasPermission) {
  325.             wrapStorage = Object.defineProperties({}, {
  326.                 "local": {
  327.                     get: delayInitLocal,
  328.                     configurable: true,
  329.                     enumerable: true
  330.                 },
  331.                 "onChanged": {
  332.                     get: delayInitOnChanged,
  333.                     configurable: true,
  334.                     enumerable: true
  335.                 }
  336.             });
  337.         }
  338.  
  339.         function parseValueFromStorage(value) {
  340.             // TODO: handle regex http://osgvsowi/2521658
  341.             if ((typeof (value) === "string") && (value.substr(0, 5) === "Date:")) {
  342.                 return new Date(JSON.parse(value.substr(5)));
  343.             } else if (typeof (value) === "string") {
  344.                 // Everything else uses JSON
  345.                 return JSON.parse(value);
  346.             }
  347.             // implicitly return undefined if value wasn't a string
  348.         }
  349.  
  350.         function delayInitLocal() {
  351.             var wrapLocal = Object.defineProperties({}, {
  352.                 "clear": {
  353.                     value: storage_local_clear_indirect.bind(nativeMsContentScript),
  354.                     configurable: true,
  355.                     enumerable: true
  356.                 },
  357.                 "get": {
  358.                     value: storage_local_get_indirect.bind(nativeMsContentScript),
  359.                     configurable: true,
  360.                     enumerable: true
  361.                 },
  362.                 "getBytesInUse": {
  363.                     value: storage_local_getBytesInUse_indirect.bind(nativeMsContentScript),
  364.                     configurable: true,
  365.                     enumerable: true
  366.                 },
  367.                 "remove": {
  368.                     value: storage_local_remove_indirect.bind(nativeMsContentScript),
  369.                     configurable: true,
  370.                     enumerable: true
  371.                 },
  372.                 "set": {
  373.                     value: storage_local_set_indirect.bind(nativeMsContentScript),
  374.                     configurable: true,
  375.                     enumerable: true
  376.                 }
  377.             });
  378.  
  379.             function TransformValuesForManager(items) {
  380.                 var keys = Object.keys(items);
  381.                 var values = {};
  382.                 for (var i = 0; i < keys.length; i++) {
  383.                     var value = items[keys[i]];
  384.                     // TODO: handle regex http://osgvsowi/2521658
  385.                     if (value instanceof Date) {
  386.                         values[keys[i]] = "Date:" + JSON.stringify(value);
  387.                     } else if (typeof value === "function") {
  388.                         // Handle functions
  389.                         values[keys[i]] = "{}";
  390.                     } else {
  391.                         // All others use JSON
  392.                         values[keys[i]] = JSON.stringify(value);
  393.                     }
  394.                 }
  395.  
  396.                 return values;
  397.             }
  398.  
  399.             function storage_local_clear_indirect() {
  400.                 // TODO (brentcou): http://osgvsowi/319342, implement storage.local.clear
  401.             }
  402.  
  403.             function storage_local_get_indirect() {
  404.                 var expectedArguments = [
  405.                     { type: "string or array or object", name: "keys", optional: true },
  406.                     { type: "function", name: "callback" }];
  407.                 TestParameterTypes("storage.local.get", arguments, expectedArguments);
  408.  
  409.                 if (GetTypeName(arguments[0]) === "array") {
  410.                     for (var i = 0; i < arguments[0].length; i++) {
  411.                         if (typeof (arguments[0][i]) !== "string") {
  412.                             ThrowArgumentError(0, "All items in the array must be strings");
  413.                         }
  414.                     }
  415.                 }
  416.  
  417.                 var keys = null;
  418.                 var callbackIndex = 0;
  419.                 if (arguments.length == 2) {
  420.                     keys = arguments[0];
  421.                     callbackIndex = 1;
  422.                 }
  423.  
  424.                 if (GetTypeName(keys) === "string") {
  425.                     // convert the single string case to an array with one element to simplify back end processing
  426.                     keys = [keys];
  427.                 }
  428.  
  429.                 if (GetTypeName(keys) === "object") {
  430.                     // if it is an object, then the values need transforming the same way they do on set.
  431.                     keys = TransformValuesForManager(keys);
  432.                 }
  433.  
  434.                 var callback = arguments[callbackIndex];
  435.                 var getCallbackWrapper = function (serializedItems) {
  436.                     var items = {};
  437.                     for (var key in serializedItems) {
  438.                         items[key] = parseValueFromStorage(serializedItems[key]);
  439.                     }
  440.  
  441.                     callback(items);
  442.                 }
  443.  
  444.                 return ExecuteGenericFunction(
  445.                     { functionId: functionId_storageLocalGet, component: componentId_manager },
  446.                     keys,
  447.                     getCallbackWrapper);
  448.             };
  449.  
  450.             function storage_local_getBytesInUse_indirect() {
  451.                 // TODO (brentcou): http://osgvsowi/319318, implement storage.local.getBytesInUse
  452.             }
  453.  
  454.             function storage_local_remove_indirect() {
  455.                 var expectedArguments = [
  456.                     { type: "string or array", name: "keys" },
  457.                     { type: "function", name: "callback", optional: true }];
  458.                 TestParameterTypes("storage.local.remove", arguments, expectedArguments);
  459.  
  460.                 if (GetTypeName(arguments[0]) === "array") {
  461.                     for (var i = 0; i < arguments[0].length; i++) {
  462.                         if (typeof (arguments[0][i]) !== "string") {
  463.                             ThrowArgumentError(0, "All items in the array must be strings");
  464.                         }
  465.                     }
  466.                 }
  467.  
  468.                 var keys = arguments[0];
  469.                 if (GetTypeName(keys) === "string") {
  470.                     // convert the single string case to an array with one element to simplify back end processing
  471.                     keys = [keys];
  472.                 }
  473.  
  474.                 var responseCallback = arguments.length > 1 ? arguments[1] : null;
  475.                 return ExecuteGenericFunction(
  476.                     { functionId: functionId_storageLocalRemove, component: componentId_manager },
  477.                     keys,
  478.                     responseCallback);
  479.             }
  480.  
  481.             function storage_local_set_indirect() {
  482.                 var expectedArguments = [
  483.                     { type: "object", name: "items" },
  484.                     { type: "function", name: "callback", optional: true }];
  485.                 TestParameterTypes("storage.local.set", arguments, expectedArguments);
  486.  
  487.                 var values = TransformValuesForManager(arguments[0]);
  488.                 var responseCallback = arguments.length > 1 ? arguments[1] : null;
  489.                 return ExecuteGenericFunction(
  490.                     { functionId: functionId_storageLocalSet, component: componentId_manager },
  491.                     values,
  492.                     responseCallback);
  493.             };
  494.  
  495.             // Replace delayInit with the initialized object to avoid repeated calls to delayInit.
  496.             Object.defineProperty(window.msBrowser.storage, "local", {
  497.                 value: wrapLocal,
  498.                 configurable: true,
  499.                 enumerable: true
  500.             });
  501.             return wrapLocal;
  502.         }
  503.  
  504.         function delayInitOnChanged() {
  505.             var onChangedObject = StoreNoFilterHandler(eventId_storageOnChanged, function (sender, storageChangeData, listeners) {
  506.                 var changes = {};
  507.                 for (var key in storageChangeData.changes) {
  508.                     var changeData = storageChangeData.changes[key];
  509.                     var parsedChangeData = {};
  510.                     parsedChangeData.oldValue = parseValueFromStorage(changeData.oldValue);
  511.                     parsedChangeData.newValue = parseValueFromStorage(changeData.newValue);
  512.                     changes[key] = parsedChangeData;
  513.                 }
  514.  
  515.                 for (var i = 0; i < listeners.length; i++) {
  516.                     if (typeof (listeners[i]) == "function") {
  517.                         listeners[i](changes, "local");
  518.                     }
  519.                 }
  520.             });
  521.  
  522.             var wrapOnChanged = Object.defineProperties({}, {
  523.                 "addListener": {
  524.                     value: onChangedObject.addListener.bind(onChangedObject),
  525.                     configurable: true,
  526.                     enumerable: true
  527.                 },
  528.                 "removeListener": {
  529.                     value: onChangedObject.removeListener.bind(onChangedObject),
  530.                     configurable: true,
  531.                     enumerable: true
  532.                 },
  533.                 "hasListener": {
  534.                     value: onChangedObject.hasListener.bind(onChangedObject),
  535.                     configurable: true,
  536.                     enumerable: true
  537.                 }
  538.             });
  539.  
  540.             // Replace delayInit with the initialized object to avoid repeated calls to delayInit.
  541.             Object.defineProperty(window.msBrowser.storage, "onChanged", {
  542.                 value: wrapOnChanged,
  543.                 configurable: true,
  544.                 enumerable: true
  545.             });
  546.             return wrapOnChanged;
  547.         }
  548.  
  549.         // Replace delayInit with the initialized object to avoid repeated calls to delayInit.
  550.         Object.defineProperty(window.msBrowser, "storage", {
  551.             value: wrapStorage,
  552.             configurable: true,
  553.             enumerable: true
  554.         });
  555.         return wrapStorage;
  556.     }
  557.  
  558.     function GetTypeName(argument) {
  559.         var type = typeof(argument);
  560.         if (type === "number") {
  561.             if (parseFloat(argument) == parseInt(argument)) {
  562.                 type = "integer";
  563.             }
  564.         } else if (type === "object") {
  565.             if (!argument) {
  566.                 type = "null";
  567.             } else if (Array.isArray(argument)) {
  568.                 type = "array";
  569.             }
  570.         }
  571.         return type;
  572.     }
  573.  
  574.     function ExecuteGenericSynchronousFunction(functionId, parameters)
  575.     {
  576.         var stringifiedParameters;
  577.         if (GetTypeName(parameters) != "undefined") {
  578.             stringifiedParameters = nativeJSON.stringify(parameters);
  579.         }
  580.  
  581.         var syncReturnString = nativeMsContentScript.genericSynchronousFunction(functionId, stringifiedParameters);
  582.  
  583.         var syncReturnValue;
  584.         if (syncReturnString) {
  585.             syncReturnValue = nativeJSON.parse(syncReturnString);
  586.         }
  587.  
  588.         return syncReturnValue;
  589.     }
  590.  
  591.     // The functions below are for parameter validation.
  592.  
  593.     function GetTypeName(argument) {
  594.         var type = typeof (argument);
  595.         if (type === "number") {
  596.             if (parseFloat(argument) == parseInt(argument)) {
  597.                 type = "integer";
  598.             }
  599.         } else if (type === "object") {
  600.             if (!argument) {
  601.                 type = "null";
  602.             } else if (Array.isArray(argument)) {
  603.                 type = "array";
  604.             }
  605.         }
  606.         return type;
  607.     }
  608.  
  609.     function TestArgumentType(argumentType, expectedArgumentType) {
  610.         if (expectedArgumentType === "any") {
  611.             return true;
  612.         } else {
  613.             var splitArgumentTypes = expectedArgumentType.split(" or ");
  614.             for (var i = 0; i < splitArgumentTypes.length; i++) {
  615.                 if (argumentType === splitArgumentTypes[i]) {
  616.                     return true;
  617.                 }
  618.             }
  619.         }
  620.         return false;
  621.     }
  622.  
  623.     function ThrowTypeError(functionName, providedArguments, expectedArguments) {
  624.         var argumentString = "";
  625.         for (var i = 0; i < providedArguments.length; i++) {
  626.             if (i > 0) {
  627.                 argumentString += ", ";
  628.             }
  629.  
  630.             argumentString += GetTypeName(providedArguments[i]);
  631.         }
  632.  
  633.         var expectedArgumentString = "";
  634.         for (var i = 0; i < expectedArguments.length; i++) {
  635.             if (i > 0) {
  636.                 expectedArgumentString += ", ";
  637.             }
  638.  
  639.             if (expectedArguments[i].optional) {
  640.                 expectedArgumentString += "optional ";
  641.             }
  642.  
  643.             expectedArgumentString += expectedArguments[i].type + " " + expectedArguments[i].name;
  644.         }
  645.  
  646.         throw "Error: Invocation of form " + functionName + "(" + argumentString + ") doesn't match definition " + functionName + "(" + expectedArgumentString + ").";
  647.     }
  648.  
  649.     function TestParameterTypes(functionName, providedArguments, expectedArguments) {
  650.         var valid = false;
  651.         var skipBits = 0;
  652.         var optionalParameterChecked = true;
  653.  
  654.         while (!valid && optionalParameterChecked) {
  655.             var currentArgumentIndex = 0;
  656.             var currentExpectedIndex = 0;
  657.             var optionalParameterIndex = 0;
  658.             optionalParameterChecked = false;
  659.             valid = true; // Innocent until proven guilty.
  660.  
  661.             for (var currentExpectedIndex = 0; currentExpectedIndex < expectedArguments.length && currentArgumentIndex < providedArguments.length && valid; currentExpectedIndex++) {
  662.                 if (expectedArguments[currentExpectedIndex].optional) {
  663.                     var bitToCheck = 1 << optionalParameterIndex;
  664.                     optionalParameterIndex++;
  665.                     if (skipBits & bitToCheck === bitToCheck) {
  666.                         continue;
  667.                     } else {
  668.                         optionalParameterChecked = true;
  669.                     }
  670.                 }
  671.  
  672.                 var argType = GetTypeName(providedArguments[currentArgumentIndex]);
  673.                 if (TestArgumentType(argType, expectedArguments[currentExpectedIndex].type)) {
  674.                     currentArgumentIndex++;
  675.                 } else if (!expectedArguments[currentExpectedIndex].optional) {
  676.                     valid = false;
  677.                     break;
  678.                 } else if (argType === "null" || argType === "undefined") {
  679.                     // optional arguments can have null or undefined in their place.
  680.                     currentArgumentIndex++;
  681.                 }
  682.             }
  683.  
  684.             if (valid) {
  685.                 for (; currentExpectedIndex < expectedArguments.length; currentExpectedIndex++) {
  686.                     if (!expectedArguments[currentExpectedIndex].optional) {
  687.                         valid = false;
  688.                         break;
  689.                     }
  690.                 }
  691.             }
  692.  
  693.             if (valid && currentArgumentIndex < providedArguments.length) {
  694.                 valid = false;
  695.             }
  696.             skipBits++;
  697.         }
  698.  
  699.         if (!valid) {
  700.             ThrowTypeError(functionName, providedArguments, expectedArguments);
  701.         }
  702.         return valid;
  703.     }
  704.  
  705.     function ThrowArgumentError(argumentIndex, errorString) {
  706.         throw "Error: Invalid value for argument " + (argumentIndex + 1) + ". " + errorString + ".";
  707.     }
  708.  
  709.     function TestObjectProperties(argumentIndex, objectToTest, propertyInformation) {
  710.         var errorString = "";
  711.         var valid = true; // Innocent until proven guilty.
  712.         var requiredProperties = {};
  713.  
  714.         for (var i = 0; i < propertyInformation.length; i++) {
  715.             if (!propertyInformation[i].optional) {
  716.                 requiredProperties[propertyInformation[i].name] = true;
  717.             }
  718.         }
  719.  
  720.         var stringPrefix = "";
  721.  
  722.         for (var prop in objectToTest) {
  723.             var found = false;
  724.             for (var i = 0; i < propertyInformation.length; i++) {
  725.                 if (prop === propertyInformation[i].name) {
  726.                     if (!propertyInformation[i].optional) {
  727.                         requiredProperties[propertyInformation[i].name] = false;
  728.                     }
  729.  
  730.                     var argType = GetTypeName(objectToTest[prop]);
  731.                     if (TestArgumentType(argType, propertyInformation[i].type)) {
  732.                         if (propertyInformation[i].validator) {
  733.                             var validationError = propertyInformation[i].validator(objectToTest[prop]);
  734.                             if (validationError) {
  735.                                 errorString += stringPrefix + "Property '" + prop + "': " + validationError;
  736.                                 stringPrefix = ", ";
  737.                                 valid = false;
  738.                             }
  739.                         }
  740.                     } else if (!propertyInformation[i].optional || (argType !== "null" && argType !== "undefined")) {
  741.                         if (propertyInformation[i].type.indexOf(" or ") === -1) {
  742.                             errorString += stringPrefix + "Property '" + prop + "': Expected '" + propertyInformation[i].type + "' but got '" + GetTypeName(objectToTest[prop]) + "'";
  743.                         } else {
  744.                             errorString += stringPrefix + "Property '" + prop + "': Value does not match any valid type choices";
  745.                         }
  746.                         stringPrefix = ", ";
  747.                         valid = false;
  748.                     }
  749.                     found = true;
  750.                     break;
  751.                 }
  752.             }
  753.  
  754.             if (!found) {
  755.                 errorString += stringPrefix + "Property '" + prop + "': Unexpected property";
  756.                 stringPrefix = ", ";
  757.                 valid = false;
  758.             }
  759.         }
  760.  
  761.         for (var prop in requiredProperties) {
  762.             if (requiredProperties[prop]) {
  763.                 errorString += stringPrefix + "Property '" + prop + "': Property is required";
  764.                 stringPrefix = ", ";
  765.                 valid = false;
  766.             }
  767.         }
  768.  
  769.         if (!valid) {
  770.             ThrowArgumentError(argumentIndex, errorString);
  771.         }
  772.         return valid;
  773.     }
  774.  
  775.     function StoreCallback(callback) {
  776.         var storedId = nextCallback;
  777.         storedCallbacks[nextCallback++] = callback;
  778.         return storedId;
  779.     }
  780.  
  781.     function InvokeCallback(callbackId, parameterString) {
  782.         if (callbackId < storedCallbacks.length && storedCallbacks[callbackId]) {
  783.             var parameters;
  784.             if (parameterString) {
  785.                 parameters = nativeJSON.parse(parameterString);
  786.             }
  787.             storedCallbacks[callbackId](parameters);
  788.             storedCallbacks[callbackId] = null;
  789.         } else {
  790.             throw "invalid callback id";
  791.         }
  792.     }
  793.  
  794.     function StoreNoFilterHandler(eventId, handlerFunc) {
  795.         var listenerHolder = {
  796.             event: eventId, handler: handlerFunc, listeners: [],
  797.             addListener: function (listener) {
  798.                 if (arguments.length > 1) {
  799.                     throw "Error: This event does not support filters.";
  800.                 }
  801.                 this.listeners.push(listener);
  802.  
  803.                 if (this.listeners.length == 1) {
  804.                     ExecuteGenericFunction({ functionId: functionId_notifyEventListener, component: componentId_manager }, this.event);
  805.                 }
  806.             },
  807.             removeListener: function (listener) {
  808.                 for (var i = 0; i < this.listeners.length; i++) {
  809.                     if (this.listeners[i] === listener) {
  810.                         this.listeners.splice(i, 1);
  811.                     }
  812.                 }
  813.             },
  814.             hasListener: function (listener) {
  815.                 for (var i = 0; i < this.listeners.length; i++) {
  816.                     if (this.listeners[i] === listener) {
  817.                         return true;
  818.                     }
  819.                 }
  820.                 return false;
  821.             }
  822.         };
  823.  
  824.         storedHandlers.push(listenerHolder);
  825.         return listenerHolder;
  826.     }
  827.  
  828.     function InvokeHandler(eventId, sender, parameterString) {
  829.         for (var i = 0; i < storedHandlers.length; i++) {
  830.             if (eventId === storedHandlers[i].event) {
  831.                 var handler = storedHandlers[i].handler;
  832.  
  833.                 var parameters;
  834.                 if (parameterString) {
  835.                     parameters = nativeJSON.parse(parameterString);
  836.                 }
  837.  
  838.                 handler(sender, parameters, storedHandlers[i].listeners);
  839.                 return true;
  840.             }
  841.         }
  842.         return false;
  843.     }
  844.  
  845.     function getRouterAddress(destination) {
  846.         var routerAddress = {};
  847.         routerAddress.a = destination.component << 28;
  848.         routerAddress.a |= destination.extensionId ?
  849.             nativeMsContentScript.extensionIdToShortId(destination.extensionId) : 0xFFFF;
  850.         routerAddress.b = 0;
  851.         routerAddress.c = 0;
  852.         routerAddress.d = destination.functionId;
  853.         return routerAddress;
  854.     }
  855.  
  856.     function ExecuteGenericFunction(destination, parameters, callback) {
  857.         if (!callback && typeof (parameters) === "function") {
  858.             callback = parameters;
  859.             parameters = null;
  860.         }
  861.  
  862.         var callbackId;
  863.         if (callback) {
  864.             callbackId = StoreCallback(callback);
  865.         }
  866.  
  867.         var stringifiedParameters;
  868.         if (GetTypeName(parameters) != "undefined") {
  869.             stringifiedParameters = nativeJSON.stringify(parameters);
  870.         }
  871.  
  872.         var routerAddress = getRouterAddress(destination);
  873.         nativeMsContentScript.genericFunction(routerAddress, stringifiedParameters, callbackId);
  874.     }
  875.  
  876.     nativeMsContentScript.registerGenericFunctionCallbackHandler(InvokeCallback);
  877.     nativeMsContentScript.registerGenericPersistentCallbackHandler(InvokeHandler);
  878.  
  879. })(window.msContentScript);
Add Comment
Please, Sign In to add comment