forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			1369 lines
		
	
	
	
		
			36 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1369 lines
		
	
	
	
		
			36 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* 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/. */
 | |
| 
 | |
| "use strict";
 | |
| 
 | |
| /**
 | |
|  * OS.File utilities used by all threads.
 | |
|  *
 | |
|  * This module defines:
 | |
|  * - logging;
 | |
|  * - the base constants;
 | |
|  * - base types and primitives for declaring new types;
 | |
|  * - primitives for importing C functions;
 | |
|  * - primitives for dealing with integers, pointers, typed arrays;
 | |
|  * - the base class OSError;
 | |
|  * - a few additional utilities.
 | |
|  */
 | |
| 
 | |
| /* eslint-env worker */
 | |
| 
 | |
| // Boilerplate used to be able to import this module both from the main
 | |
| // thread and from worker threads.
 | |
| 
 | |
| /**
 | |
|  * A constructor for messages that require transfers instead of copies.
 | |
|  *
 | |
|  * See BasePromiseWorker.Meta.
 | |
|  *
 | |
|  * @constructor
 | |
|  */
 | |
| var Meta;
 | |
| if (typeof Components != "undefined") {
 | |
|   // Global definition of |exports|, to keep everybody happy.
 | |
|   // In non-main thread, |exports| is provided by the module
 | |
|   // loader.
 | |
|   // eslint-disable-next-line mozilla/reject-global-this
 | |
|   this.exports = {};
 | |
|   Meta = ChromeUtils.import("resource://gre/modules/PromiseWorker.jsm")
 | |
|     .BasePromiseWorker.Meta;
 | |
| } else {
 | |
|   /* import-globals-from /toolkit/components/workerloader/require.js */
 | |
|   importScripts("resource://gre/modules/workers/require.js");
 | |
|   Meta = require("resource://gre/modules/workers/PromiseWorker.js").Meta;
 | |
| }
 | |
| 
 | |
| var EXPORTED_SYMBOLS = [
 | |
|   "LOG",
 | |
|   "clone",
 | |
|   "Config",
 | |
|   "Constants",
 | |
|   "Type",
 | |
|   "HollowStructure",
 | |
|   "OSError",
 | |
|   "Library",
 | |
|   "declareFFI",
 | |
|   "declareLazy",
 | |
|   "declareLazyFFI",
 | |
|   "normalizeBufferArgs",
 | |
|   "projectValue",
 | |
|   "isArrayBuffer",
 | |
|   "isTypedArray",
 | |
|   "defineLazyGetter",
 | |
|   "OS", // Warning: this exported symbol will disappear
 | |
| ];
 | |
| 
 | |
| // //////////////////// Configuration of OS.File
 | |
| 
 | |
| var Config = {
 | |
|   /**
 | |
|    * If |true|, calls to |LOG| are shown. Otherwise, they are hidden.
 | |
|    *
 | |
|    * This configuration option is controlled by preference "toolkit.osfile.log".
 | |
|    */
 | |
|   DEBUG: false,
 | |
| 
 | |
|   /**
 | |
|    * TEST
 | |
|    */
 | |
|   TEST: false,
 | |
| };
 | |
| exports.Config = Config;
 | |
| 
 | |
| // //////////////////// OS Constants
 | |
| 
 | |
| if (typeof Components != "undefined") {
 | |
|   // On the main thread, OS.Constants is defined by a xpcom
 | |
|   // component. On other threads, it is available automatically
 | |
|   /* global OS */
 | |
|   var { ctypes } = ChromeUtils.import("resource://gre/modules/ctypes.jsm");
 | |
|   Cc["@mozilla.org/net/osfileconstantsservice;1"]
 | |
|     .getService(Ci.nsIOSFileConstantsService)
 | |
|     .init();
 | |
| } else {
 | |
|   ctypes = self.ctypes;
 | |
| }
 | |
| 
 | |
| exports.Constants = OS.Constants;
 | |
| 
 | |
| // /////////////////// Utilities
 | |
| 
 | |
| // Define a lazy getter for a property
 | |
| var defineLazyGetter = function defineLazyGetter(object, name, getter) {
 | |
|   Object.defineProperty(object, name, {
 | |
|     configurable: true,
 | |
|     get: function lazy() {
 | |
|       delete this[name];
 | |
|       let value = getter.call(this);
 | |
|       Object.defineProperty(object, name, {
 | |
|         value,
 | |
|       });
 | |
|       return value;
 | |
|     },
 | |
|   });
 | |
| };
 | |
| exports.defineLazyGetter = defineLazyGetter;
 | |
| 
 | |
| // /////////////////// Logging
 | |
| 
 | |
| /**
 | |
|  * The default implementation of the logger.
 | |
|  *
 | |
|  * The choice of logger can be overridden with Config.TEST.
 | |
|  */
 | |
| var gLogger;
 | |
| // eslint-disable-next-line no-undef
 | |
| if (typeof window != "undefined" && window.console && console.log) {
 | |
|   gLogger = console.log.bind(console, "OS");
 | |
| } else {
 | |
|   gLogger = function(...args) {
 | |
|     dump("OS " + args.join(" ") + "\n");
 | |
|   };
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Attempt to stringify an argument into something useful for
 | |
|  * debugging purposes, by using |.toString()| or |JSON.stringify|
 | |
|  * if available.
 | |
|  *
 | |
|  * @param {*} arg An argument to be stringified if possible.
 | |
|  * @return {string} A stringified version of |arg|.
 | |
|  */
 | |
| var stringifyArg = function stringifyArg(arg) {
 | |
|   if (typeof arg === "string") {
 | |
|     return arg;
 | |
|   }
 | |
|   if (arg && typeof arg === "object") {
 | |
|     let argToString = "" + arg;
 | |
| 
 | |
|     /**
 | |
|      * The only way to detect whether this object has a non-default
 | |
|      * implementation of |toString| is to check whether it returns
 | |
|      * '[object Object]'. Unfortunately, we cannot simply compare |arg.toString|
 | |
|      * and |Object.prototype.toString| as |arg| typically comes from another
 | |
|      * compartment.
 | |
|      */
 | |
|     if (argToString === "[object Object]") {
 | |
|       return JSON.stringify(arg, function(key, value) {
 | |
|         if (isTypedArray(value)) {
 | |
|           return (
 | |
|             "[" +
 | |
|             value.constructor.name +
 | |
|             " " +
 | |
|             value.byteOffset +
 | |
|             " " +
 | |
|             value.byteLength +
 | |
|             "]"
 | |
|           );
 | |
|         }
 | |
|         if (isArrayBuffer(arg)) {
 | |
|           return "[" + value.constructor.name + " " + value.byteLength + "]";
 | |
|         }
 | |
|         return value;
 | |
|       });
 | |
|     }
 | |
|     return argToString;
 | |
|   }
 | |
|   return arg;
 | |
| };
 | |
| 
 | |
| var LOG = function(...args) {
 | |
|   if (!Config.DEBUG) {
 | |
|     // If logging is deactivated, don't log
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   let logFunc = gLogger;
 | |
|   if (Config.TEST && typeof Components != "undefined") {
 | |
|     // If _TESTING_LOGGING is set, and if we are on the main thread,
 | |
|     // redirect logs to Services.console, for testing purposes
 | |
|     logFunc = function logFunc(...args) {
 | |
|       let message = ["TEST", "OS"].concat(args).join(" ");
 | |
|       Services.console.logStringMessage(message + "\n");
 | |
|     };
 | |
|   }
 | |
|   logFunc.apply(null, args.map(stringifyArg));
 | |
| };
 | |
| 
 | |
| exports.LOG = LOG;
 | |
| 
 | |
| /**
 | |
|  * Return a shallow clone of the enumerable properties of an object.
 | |
|  *
 | |
|  * Utility used whenever normalizing options requires making (shallow)
 | |
|  * changes to an option object. The copy ensures that we do not modify
 | |
|  * a client-provided object by accident.
 | |
|  *
 | |
|  * Note: to reference and not copy specific fields, provide an optional
 | |
|  * |refs| argument containing their names.
 | |
|  *
 | |
|  * @param {JSON} object Options to be cloned.
 | |
|  * @param {Array} refs An optional array of field names to be passed by
 | |
|  * reference instead of copying.
 | |
|  */
 | |
| var clone = function(object, refs = []) {
 | |
|   let result = {};
 | |
|   // Make a reference between result[key] and object[key].
 | |
|   let refer = function refer(result, key, object) {
 | |
|     Object.defineProperty(result, key, {
 | |
|       enumerable: true,
 | |
|       get() {
 | |
|         return object[key];
 | |
|       },
 | |
|       set(value) {
 | |
|         object[key] = value;
 | |
|       },
 | |
|     });
 | |
|   };
 | |
|   for (let k in object) {
 | |
|     if (!refs.includes(k)) {
 | |
|       result[k] = object[k];
 | |
|     } else {
 | |
|       refer(result, k, object);
 | |
|     }
 | |
|   }
 | |
|   return result;
 | |
| };
 | |
| 
 | |
| exports.clone = clone;
 | |
| 
 | |
| // /////////////////// Abstractions above js-ctypes
 | |
| 
 | |
| /**
 | |
|  * Abstraction above js-ctypes types.
 | |
|  *
 | |
|  * Use values of this type to register FFI functions. In addition to the
 | |
|  * usual features of js-ctypes, values of this type perform the necessary
 | |
|  * transformations to ensure that C errors are handled nicely, to connect
 | |
|  * resources with their finalizer, etc.
 | |
|  *
 | |
|  * @param {string} name The name of the type. Must be unique.
 | |
|  * @param {CType} implementation The js-ctypes implementation of the type.
 | |
|  *
 | |
|  * @constructor
 | |
|  */
 | |
| function Type(name, implementation) {
 | |
|   if (!(typeof name == "string")) {
 | |
|     throw new TypeError("Type expects as first argument a name, got: " + name);
 | |
|   }
 | |
|   if (!(implementation instanceof ctypes.CType)) {
 | |
|     throw new TypeError(
 | |
|       "Type expects as second argument a ctypes.CType" +
 | |
|         ", got: " +
 | |
|         implementation
 | |
|     );
 | |
|   }
 | |
|   Object.defineProperty(this, "name", { value: name });
 | |
|   Object.defineProperty(this, "implementation", { value: implementation });
 | |
| }
 | |
| Type.prototype = {
 | |
|   /**
 | |
|    * Serialize a value of |this| |Type| into a format that can
 | |
|    * be transmitted as a message (not necessarily a string).
 | |
|    *
 | |
|    * In the default implementation, the method returns the
 | |
|    * value unchanged.
 | |
|    */
 | |
|   toMsg: function default_toMsg(value) {
 | |
|     return value;
 | |
|   },
 | |
|   /**
 | |
|    * Deserialize a message to a value of |this| |Type|.
 | |
|    *
 | |
|    * In the default implementation, the method returns the
 | |
|    * message unchanged.
 | |
|    */
 | |
|   fromMsg: function default_fromMsg(msg) {
 | |
|     return msg;
 | |
|   },
 | |
|   /**
 | |
|    * Import a value from C.
 | |
|    *
 | |
|    * In this default implementation, return the value
 | |
|    * unchanged.
 | |
|    */
 | |
|   importFromC: function default_importFromC(value) {
 | |
|     return value;
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * A pointer/array used to pass data to the foreign function.
 | |
|    */
 | |
|   get in_ptr() {
 | |
|     delete this.in_ptr;
 | |
|     let ptr_t = new PtrType(
 | |
|       "[in] " + this.name + "*",
 | |
|       this.implementation.ptr,
 | |
|       this
 | |
|     );
 | |
|     Object.defineProperty(this, "in_ptr", {
 | |
|       get() {
 | |
|         return ptr_t;
 | |
|       },
 | |
|     });
 | |
|     return ptr_t;
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * A pointer/array used to receive data from the foreign function.
 | |
|    */
 | |
|   get out_ptr() {
 | |
|     delete this.out_ptr;
 | |
|     let ptr_t = new PtrType(
 | |
|       "[out] " + this.name + "*",
 | |
|       this.implementation.ptr,
 | |
|       this
 | |
|     );
 | |
|     Object.defineProperty(this, "out_ptr", {
 | |
|       get() {
 | |
|         return ptr_t;
 | |
|       },
 | |
|     });
 | |
|     return ptr_t;
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * A pointer/array used to both pass data to the foreign function
 | |
|    * and receive data from the foreign function.
 | |
|    *
 | |
|    * Whenever possible, prefer using |in_ptr| or |out_ptr|, which
 | |
|    * are generally faster.
 | |
|    */
 | |
|   get inout_ptr() {
 | |
|     delete this.inout_ptr;
 | |
|     let ptr_t = new PtrType(
 | |
|       "[inout] " + this.name + "*",
 | |
|       this.implementation.ptr,
 | |
|       this
 | |
|     );
 | |
|     Object.defineProperty(this, "inout_ptr", {
 | |
|       get() {
 | |
|         return ptr_t;
 | |
|       },
 | |
|     });
 | |
|     return ptr_t;
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * Attach a finalizer to a type.
 | |
|    */
 | |
|   releaseWith: function releaseWith(finalizer) {
 | |
|     let parent = this;
 | |
|     let type = this.withName("[auto " + this.name + ", " + finalizer + "] ");
 | |
|     type.importFromC = function importFromC(value, operation) {
 | |
|       return ctypes.CDataFinalizer(
 | |
|         parent.importFromC(value, operation),
 | |
|         finalizer
 | |
|       );
 | |
|     };
 | |
|     return type;
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * Lazy variant of releaseWith.
 | |
|    * Attach a finalizer lazily to a type.
 | |
|    *
 | |
|    * @param {function} getFinalizer The function that
 | |
|    * returns finalizer lazily.
 | |
|    */
 | |
|   releaseWithLazy: function releaseWithLazy(getFinalizer) {
 | |
|     let parent = this;
 | |
|     let type = this.withName("[auto " + this.name + ", (lazy)] ");
 | |
|     type.importFromC = function importFromC(value, operation) {
 | |
|       return ctypes.CDataFinalizer(
 | |
|         parent.importFromC(value, operation),
 | |
|         getFinalizer()
 | |
|       );
 | |
|     };
 | |
|     return type;
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * Return an alias to a type with a different name.
 | |
|    */
 | |
|   withName: function withName(name) {
 | |
|     return Object.create(this, { name: { value: name } });
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * Cast a C value to |this| type.
 | |
|    *
 | |
|    * Throw an error if the value cannot be casted.
 | |
|    */
 | |
|   cast: function cast(value) {
 | |
|     return ctypes.cast(value, this.implementation);
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * Return the number of bytes in a value of |this| type.
 | |
|    *
 | |
|    * This may not be defined, e.g. for |void_t|, array types
 | |
|    * without length, etc.
 | |
|    */
 | |
|   get size() {
 | |
|     return this.implementation.size;
 | |
|   },
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Utility function used to determine whether an object is a typed array
 | |
|  */
 | |
| var isTypedArray = function isTypedArray(obj) {
 | |
|   return obj != null && typeof obj == "object" && "byteOffset" in obj;
 | |
| };
 | |
| exports.isTypedArray = isTypedArray;
 | |
| 
 | |
| /**
 | |
|  * Utility function used to determine whether an object is an ArrayBuffer.
 | |
|  */
 | |
| var isArrayBuffer = function(obj) {
 | |
|   return (
 | |
|     obj != null &&
 | |
|     typeof obj == "object" &&
 | |
|     obj.constructor.name == "ArrayBuffer"
 | |
|   );
 | |
| };
 | |
| exports.isArrayBuffer = isArrayBuffer;
 | |
| 
 | |
| /**
 | |
|  * A |Type| of pointers.
 | |
|  *
 | |
|  * @param {string} name The name of this type.
 | |
|  * @param {CType} implementation The type of this pointer.
 | |
|  * @param {Type} targetType The target type.
 | |
|  */
 | |
| function PtrType(name, implementation, targetType) {
 | |
|   Type.call(this, name, implementation);
 | |
|   if (targetType == null || !(targetType instanceof Type)) {
 | |
|     throw new TypeError("targetType must be an instance of Type");
 | |
|   }
 | |
|   /**
 | |
|    * The type of values targeted by this pointer type.
 | |
|    */
 | |
|   Object.defineProperty(this, "targetType", {
 | |
|     value: targetType,
 | |
|   });
 | |
| }
 | |
| PtrType.prototype = Object.create(Type.prototype);
 | |
| 
 | |
| /**
 | |
|  * Convert a value to a pointer.
 | |
|  *
 | |
|  * Protocol:
 | |
|  * - |null| returns |null|
 | |
|  * - a string returns |{string: value}|
 | |
|  * - a typed array returns |{ptr: address_of_buffer}|
 | |
|  * - a C array returns |{ptr: address_of_buffer}|
 | |
|  * everything else raises an error
 | |
|  */
 | |
| PtrType.prototype.toMsg = function ptr_toMsg(value) {
 | |
|   if (value == null) {
 | |
|     return null;
 | |
|   }
 | |
|   if (typeof value == "string") {
 | |
|     return { string: value };
 | |
|   }
 | |
|   if (isTypedArray(value)) {
 | |
|     // Automatically transfer typed arrays
 | |
|     return new Meta({ data: value }, { transfers: [value.buffer] });
 | |
|   }
 | |
|   if (isArrayBuffer(value)) {
 | |
|     // Automatically transfer array buffers
 | |
|     return new Meta({ data: value }, { transfers: [value] });
 | |
|   }
 | |
|   let normalized;
 | |
|   if ("addressOfElement" in value) {
 | |
|     // C array
 | |
|     normalized = value.addressOfElement(0);
 | |
|   } else if ("isNull" in value) {
 | |
|     // C pointer
 | |
|     normalized = value;
 | |
|   } else {
 | |
|     throw new TypeError("Value " + value + " cannot be converted to a pointer");
 | |
|   }
 | |
|   let cast = Type.uintptr_t.cast(normalized);
 | |
|   return { ptr: cast.value.toString() };
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Convert a message back to a pointer.
 | |
|  */
 | |
| PtrType.prototype.fromMsg = function ptr_fromMsg(msg) {
 | |
|   if (msg == null) {
 | |
|     return null;
 | |
|   }
 | |
|   if ("string" in msg) {
 | |
|     return msg.string;
 | |
|   }
 | |
|   if ("data" in msg) {
 | |
|     return msg.data;
 | |
|   }
 | |
|   if ("ptr" in msg) {
 | |
|     let address = ctypes.uintptr_t(msg.ptr);
 | |
|     return this.cast(address);
 | |
|   }
 | |
|   throw new TypeError(
 | |
|     "Message " + msg.toSource() + " does not represent a pointer"
 | |
|   );
 | |
| };
 | |
| 
 | |
| exports.Type = Type;
 | |
| 
 | |
| /*
 | |
|  * Some values are large integers on 64 bit platforms. Unfortunately,
 | |
|  * in practice, 64 bit integers cannot be manipulated in JS. We
 | |
|  * therefore project them to regular numbers whenever possible.
 | |
|  */
 | |
| 
 | |
| var projectLargeInt = function projectLargeInt(x) {
 | |
|   let str = x.toString();
 | |
|   let rv = parseInt(str, 10);
 | |
|   if (rv.toString() !== str) {
 | |
|     throw new TypeError("Number " + str + " cannot be projected to a double");
 | |
|   }
 | |
|   return rv;
 | |
| };
 | |
| var projectLargeUInt = function projectLargeUInt(x) {
 | |
|   return projectLargeInt(x);
 | |
| };
 | |
| var projectValue = function projectValue(x) {
 | |
|   if (!(x instanceof ctypes.CData)) {
 | |
|     return x;
 | |
|   }
 | |
|   if (!("value" in x)) {
 | |
|     // Sanity check
 | |
|     throw new TypeError("Number " + x.toSource() + " has no field |value|");
 | |
|   }
 | |
|   return x.value;
 | |
| };
 | |
| 
 | |
| function projector(type, signed) {
 | |
|   LOG(
 | |
|     "Determining best projection for",
 | |
|     type,
 | |
|     "(size: ",
 | |
|     type.size,
 | |
|     ")",
 | |
|     signed ? "signed" : "unsigned"
 | |
|   );
 | |
|   if (type instanceof Type) {
 | |
|     type = type.implementation;
 | |
|   }
 | |
|   if (!type.size) {
 | |
|     throw new TypeError("Argument is not a proper C type");
 | |
|   }
 | |
|   // Determine if type is projected to Int64/Uint64
 | |
|   if (
 | |
|     type.size == 8 || // Usual case
 | |
|     // The following cases have special treatment in js-ctypes
 | |
|     // Regardless of their size, the value getter returns
 | |
|     // a Int64/Uint64
 | |
|     type == ctypes.size_t || // Special cases
 | |
|     type == ctypes.ssize_t ||
 | |
|     type == ctypes.intptr_t ||
 | |
|     type == ctypes.uintptr_t ||
 | |
|     type == ctypes.off_t
 | |
|   ) {
 | |
|     if (signed) {
 | |
|       LOG("Projected as a large signed integer");
 | |
|       return projectLargeInt;
 | |
|     }
 | |
|     LOG("Projected as a large unsigned integer");
 | |
|     return projectLargeUInt;
 | |
|   }
 | |
|   LOG("Projected as a regular number");
 | |
|   return projectValue;
 | |
| }
 | |
| exports.projectValue = projectValue;
 | |
| 
 | |
| /**
 | |
|  * Get the appropriate type for an unsigned int of the given size.
 | |
|  *
 | |
|  * This function is useful to define types such as |mode_t| whose
 | |
|  * actual width depends on the OS/platform.
 | |
|  *
 | |
|  * @param {number} size The number of bytes requested.
 | |
|  */
 | |
| Type.uintn_t = function uintn_t(size) {
 | |
|   switch (size) {
 | |
|     case 1:
 | |
|       return Type.uint8_t;
 | |
|     case 2:
 | |
|       return Type.uint16_t;
 | |
|     case 4:
 | |
|       return Type.uint32_t;
 | |
|     case 8:
 | |
|       return Type.uint64_t;
 | |
|     default:
 | |
|       throw new Error(
 | |
|         "Cannot represent unsigned integers of " + size + " bytes"
 | |
|       );
 | |
|   }
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Get the appropriate type for an signed int of the given size.
 | |
|  *
 | |
|  * This function is useful to define types such as |mode_t| whose
 | |
|  * actual width depends on the OS/platform.
 | |
|  *
 | |
|  * @param {number} size The number of bytes requested.
 | |
|  */
 | |
| Type.intn_t = function intn_t(size) {
 | |
|   switch (size) {
 | |
|     case 1:
 | |
|       return Type.int8_t;
 | |
|     case 2:
 | |
|       return Type.int16_t;
 | |
|     case 4:
 | |
|       return Type.int32_t;
 | |
|     case 8:
 | |
|       return Type.int64_t;
 | |
|     default:
 | |
|       throw new Error("Cannot represent integers of " + size + " bytes");
 | |
|   }
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Actual implementation of common C types.
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * The void value.
 | |
|  */
 | |
| Type.void_t = new Type("void", ctypes.void_t);
 | |
| 
 | |
| /**
 | |
|  * Shortcut for |void*|.
 | |
|  */
 | |
| Type.voidptr_t = new PtrType("void*", ctypes.voidptr_t, Type.void_t);
 | |
| 
 | |
| // void* is a special case as we can cast any pointer to/from it
 | |
| // so we have to shortcut |in_ptr|/|out_ptr|/|inout_ptr| and
 | |
| // ensure that js-ctypes' casting mechanism is invoked directly
 | |
| ["in_ptr", "out_ptr", "inout_ptr"].forEach(function(key) {
 | |
|   Object.defineProperty(Type.void_t, key, {
 | |
|     value: Type.voidptr_t,
 | |
|   });
 | |
| });
 | |
| 
 | |
| /**
 | |
|  * A Type of integers.
 | |
|  *
 | |
|  * @param {string} name The name of this type.
 | |
|  * @param {CType} implementation The underlying js-ctypes implementation.
 | |
|  * @param {bool} signed |true| if this is a type of signed integers,
 | |
|  * |false| otherwise.
 | |
|  *
 | |
|  * @constructor
 | |
|  */
 | |
| function IntType(name, implementation, signed) {
 | |
|   Type.call(this, name, implementation);
 | |
|   this.importFromC = projector(implementation, signed);
 | |
|   this.project = this.importFromC;
 | |
| }
 | |
| IntType.prototype = Object.create(Type.prototype);
 | |
| IntType.prototype.toMsg = function toMsg(value) {
 | |
|   if (typeof value == "number") {
 | |
|     return value;
 | |
|   }
 | |
|   return this.project(value);
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * A C char (one byte)
 | |
|  */
 | |
| Type.char = new Type("char", ctypes.char);
 | |
| 
 | |
| /**
 | |
|  * A C wide char (two bytes)
 | |
|  */
 | |
| Type.char16_t = new Type("char16_t", ctypes.char16_t);
 | |
| 
 | |
| /**
 | |
|  * Base string types.
 | |
|  */
 | |
| Type.cstring = Type.char.in_ptr.withName("[in] C string");
 | |
| Type.wstring = Type.char16_t.in_ptr.withName("[in] wide string");
 | |
| Type.out_cstring = Type.char.out_ptr.withName("[out] C string");
 | |
| Type.out_wstring = Type.char16_t.out_ptr.withName("[out] wide string");
 | |
| 
 | |
| /**
 | |
|  * A C integer (8-bits).
 | |
|  */
 | |
| Type.int8_t = new IntType("int8_t", ctypes.int8_t, true);
 | |
| 
 | |
| Type.uint8_t = new IntType("uint8_t", ctypes.uint8_t, false);
 | |
| 
 | |
| /**
 | |
|  * A C integer (16-bits).
 | |
|  *
 | |
|  * Also known as WORD under Windows.
 | |
|  */
 | |
| Type.int16_t = new IntType("int16_t", ctypes.int16_t, true);
 | |
| 
 | |
| Type.uint16_t = new IntType("uint16_t", ctypes.uint16_t, false);
 | |
| 
 | |
| /**
 | |
|  * A C integer (32-bits).
 | |
|  *
 | |
|  * Also known as DWORD under Windows.
 | |
|  */
 | |
| Type.int32_t = new IntType("int32_t", ctypes.int32_t, true);
 | |
| 
 | |
| Type.uint32_t = new IntType("uint32_t", ctypes.uint32_t, false);
 | |
| 
 | |
| /**
 | |
|  * A C integer (64-bits).
 | |
|  */
 | |
| Type.int64_t = new IntType("int64_t", ctypes.int64_t, true);
 | |
| 
 | |
| Type.uint64_t = new IntType("uint64_t", ctypes.uint64_t, false);
 | |
| 
 | |
| /**
 | |
|  * A C integer
 | |
|  *
 | |
|  * Size depends on the platform.
 | |
|  */
 | |
| Type.int = Type.intn_t(ctypes.int.size).withName("int");
 | |
| 
 | |
| Type.unsigned_int = Type.intn_t(ctypes.unsigned_int.size).withName(
 | |
|   "unsigned int"
 | |
| );
 | |
| 
 | |
| /**
 | |
|  * A C long integer.
 | |
|  *
 | |
|  * Size depends on the platform.
 | |
|  */
 | |
| Type.long = Type.intn_t(ctypes.long.size).withName("long");
 | |
| 
 | |
| Type.unsigned_long = Type.intn_t(ctypes.unsigned_long.size).withName(
 | |
|   "unsigned long"
 | |
| );
 | |
| 
 | |
| /**
 | |
|  * An unsigned integer with the same size as a pointer.
 | |
|  *
 | |
|  * Used to cast a pointer to an integer, whenever necessary.
 | |
|  */
 | |
| Type.uintptr_t = Type.uintn_t(ctypes.uintptr_t.size).withName("uintptr_t");
 | |
| 
 | |
| /**
 | |
|  * A boolean.
 | |
|  * Implemented as a C integer.
 | |
|  */
 | |
| Type.bool = Type.int.withName("bool");
 | |
| Type.bool.importFromC = function projectBool(x) {
 | |
|   return !!x.value;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * A user identifier.
 | |
|  *
 | |
|  * Implemented as a C integer.
 | |
|  */
 | |
| Type.uid_t = Type.int.withName("uid_t");
 | |
| 
 | |
| /**
 | |
|  * A group identifier.
 | |
|  *
 | |
|  * Implemented as a C integer.
 | |
|  */
 | |
| Type.gid_t = Type.int.withName("gid_t");
 | |
| 
 | |
| /**
 | |
|  * An offset (positive or negative).
 | |
|  *
 | |
|  * Implemented as a C integer.
 | |
|  */
 | |
| Type.off_t = new IntType("off_t", ctypes.off_t, true);
 | |
| 
 | |
| /**
 | |
|  * A size (positive).
 | |
|  *
 | |
|  * Implemented as a C size_t.
 | |
|  */
 | |
| Type.size_t = new IntType("size_t", ctypes.size_t, false);
 | |
| 
 | |
| /**
 | |
|  * An offset (positive or negative).
 | |
|  * Implemented as a C integer.
 | |
|  */
 | |
| Type.ssize_t = new IntType("ssize_t", ctypes.ssize_t, true);
 | |
| 
 | |
| /**
 | |
|  * Encoding/decoding strings
 | |
|  */
 | |
| Type.uencoder = new Type("uencoder", ctypes.StructType("uencoder"));
 | |
| Type.udecoder = new Type("udecoder", ctypes.StructType("udecoder"));
 | |
| 
 | |
| /**
 | |
|  * Utility class, used to build a |struct| type
 | |
|  * from a set of field names, types and offsets.
 | |
|  *
 | |
|  * @param {string} name The name of the |struct| type.
 | |
|  * @param {number} size The total size of the |struct| type in bytes.
 | |
|  */
 | |
| function HollowStructure(name, size) {
 | |
|   if (!name) {
 | |
|     throw new TypeError("HollowStructure expects a name");
 | |
|   }
 | |
|   if (!size || size < 0) {
 | |
|     throw new TypeError("HollowStructure expects a (positive) size");
 | |
|   }
 | |
| 
 | |
|   // A mapping from offsets in the struct to name/type pairs
 | |
|   // (or nothing if no field starts at that offset).
 | |
|   this.offset_to_field_info = [];
 | |
| 
 | |
|   // The name of the struct
 | |
|   this.name = name;
 | |
| 
 | |
|   // The size of the struct, in bytes
 | |
|   this.size = size;
 | |
| 
 | |
|   // The number of paddings inserted so far.
 | |
|   // Used to give distinct names to padding fields.
 | |
|   this._paddings = 0;
 | |
| }
 | |
| HollowStructure.prototype = {
 | |
|   /**
 | |
|    * Add a field at a given offset.
 | |
|    *
 | |
|    * @param {number} offset The offset at which to insert the field.
 | |
|    * @param {string} name The name of the field.
 | |
|    * @param {CType|Type} type The type of the field.
 | |
|    */
 | |
|   add_field_at: function add_field_at(offset, name, type) {
 | |
|     if (offset == null) {
 | |
|       throw new TypeError("add_field_at requires a non-null offset");
 | |
|     }
 | |
|     if (!name) {
 | |
|       throw new TypeError("add_field_at requires a non-null name");
 | |
|     }
 | |
|     if (!type) {
 | |
|       throw new TypeError("add_field_at requires a non-null type");
 | |
|     }
 | |
|     if (type instanceof Type) {
 | |
|       type = type.implementation;
 | |
|     }
 | |
|     if (this.offset_to_field_info[offset]) {
 | |
|       throw new Error(
 | |
|         "HollowStructure " +
 | |
|           this.name +
 | |
|           " already has a field at offset " +
 | |
|           offset
 | |
|       );
 | |
|     }
 | |
|     if (offset + type.size > this.size) {
 | |
|       throw new Error(
 | |
|         "HollowStructure " +
 | |
|           this.name +
 | |
|           " cannot place a value of type " +
 | |
|           type +
 | |
|           " at offset " +
 | |
|           offset +
 | |
|           " without exceeding its size of " +
 | |
|           this.size
 | |
|       );
 | |
|     }
 | |
|     let field = { name, type };
 | |
|     this.offset_to_field_info[offset] = field;
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * Create a pseudo-field that will only serve as padding.
 | |
|    *
 | |
|    * @param {number} size The number of bytes in the field.
 | |
|    * @return {Object} An association field-name => field-type,
 | |
|    * as expected by |ctypes.StructType|.
 | |
|    */
 | |
|   _makePaddingField: function makePaddingField(size) {
 | |
|     let field = {};
 | |
|     field["padding_" + this._paddings] = ctypes.ArrayType(ctypes.uint8_t, size);
 | |
|     this._paddings++;
 | |
|     return field;
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * Convert this |HollowStructure| into a |Type|.
 | |
|    */
 | |
|   getType: function getType() {
 | |
|     // Contents of the structure, in the format expected
 | |
|     // by ctypes.StructType.
 | |
|     let struct = [];
 | |
| 
 | |
|     let i = 0;
 | |
|     while (i < this.size) {
 | |
|       let currentField = this.offset_to_field_info[i];
 | |
|       if (!currentField) {
 | |
|         // No field was specified at this offset, we need to
 | |
|         // introduce some padding.
 | |
| 
 | |
|         // Firstly, determine how many bytes of padding
 | |
|         let padding_length = 1;
 | |
|         while (
 | |
|           i + padding_length < this.size &&
 | |
|           !this.offset_to_field_info[i + padding_length]
 | |
|         ) {
 | |
|           ++padding_length;
 | |
|         }
 | |
| 
 | |
|         // Then add the padding
 | |
|         struct.push(this._makePaddingField(padding_length));
 | |
| 
 | |
|         // And proceed
 | |
|         i += padding_length;
 | |
|       } else {
 | |
|         // We have a field at this offset.
 | |
| 
 | |
|         // Firstly, ensure that we do not have two overlapping fields
 | |
|         for (let j = 1; j < currentField.type.size; ++j) {
 | |
|           let candidateField = this.offset_to_field_info[i + j];
 | |
|           if (candidateField) {
 | |
|             throw new Error(
 | |
|               "Fields " +
 | |
|                 currentField.name +
 | |
|                 " and " +
 | |
|                 candidateField.name +
 | |
|                 " overlap at position " +
 | |
|                 (i + j)
 | |
|             );
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         // Then add the field
 | |
|         let field = {};
 | |
|         field[currentField.name] = currentField.type;
 | |
|         struct.push(field);
 | |
| 
 | |
|         // And proceed
 | |
|         i += currentField.type.size;
 | |
|       }
 | |
|     }
 | |
|     let result = new Type(this.name, ctypes.StructType(this.name, struct));
 | |
|     if (result.implementation.size != this.size) {
 | |
|       throw new Error(
 | |
|         "Wrong size for type " +
 | |
|           this.name +
 | |
|           ": expected " +
 | |
|           this.size +
 | |
|           ", found " +
 | |
|           result.implementation.size +
 | |
|           " (" +
 | |
|           result.implementation.toSource() +
 | |
|           ")"
 | |
|       );
 | |
|     }
 | |
|     return result;
 | |
|   },
 | |
| };
 | |
| exports.HollowStructure = HollowStructure;
 | |
| 
 | |
| /**
 | |
|  * Representation of a native library.
 | |
|  *
 | |
|  * The native library is opened lazily, during the first call to its
 | |
|  * field |library| or whenever accessing one of the methods imported
 | |
|  * with declareLazyFFI.
 | |
|  *
 | |
|  * @param {string} name A human-readable name for the library. Used
 | |
|  * for debugging and error reporting.
 | |
|  * @param {string...} candidates A list of system libraries that may
 | |
|  * represent this library. Used e.g. to try different library names
 | |
|  * on distinct operating systems ("libxul", "XUL", etc.).
 | |
|  *
 | |
|  * @constructor
 | |
|  */
 | |
| function Library(name, ...candidates) {
 | |
|   this.name = name;
 | |
|   this._candidates = candidates;
 | |
| }
 | |
| Library.prototype = Object.freeze({
 | |
|   /**
 | |
|    * The native library as a js-ctypes object.
 | |
|    *
 | |
|    * @throws {Error} If none of the candidate libraries could be opened.
 | |
|    */
 | |
|   get library() {
 | |
|     let library;
 | |
|     delete this.library;
 | |
|     for (let candidate of this._candidates) {
 | |
|       try {
 | |
|         library = ctypes.open(candidate);
 | |
|         break;
 | |
|       } catch (ex) {
 | |
|         LOG("Could not open library", candidate, ex);
 | |
|       }
 | |
|     }
 | |
|     this._candidates = null;
 | |
|     if (library) {
 | |
|       Object.defineProperty(this, "library", {
 | |
|         value: library,
 | |
|       });
 | |
|       Object.freeze(this);
 | |
|       return library;
 | |
|     }
 | |
|     let error = new Error("Could not open library " + this.name);
 | |
|     Object.defineProperty(this, "library", {
 | |
|       get() {
 | |
|         throw error;
 | |
|       },
 | |
|     });
 | |
|     Object.freeze(this);
 | |
|     throw error;
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * Declare a function, lazily.
 | |
|    *
 | |
|    * @param {object} The object containing the function as a field.
 | |
|    * @param {string} The name of the field containing the function.
 | |
|    * @param {string} symbol The name of the function, as defined in the
 | |
|    * library.
 | |
|    * @param {ctypes.abi} abi The abi to use, or |null| for default.
 | |
|    * @param {Type} returnType The type of values returned by the function.
 | |
|    * @param {...Type} argTypes The type of arguments to the function.
 | |
|    */
 | |
|   declareLazyFFI(object, field, ...args) {
 | |
|     let lib = this;
 | |
|     Object.defineProperty(object, field, {
 | |
|       get() {
 | |
|         delete this[field];
 | |
|         let ffi = declareFFI(lib.library, ...args);
 | |
|         if (ffi) {
 | |
|           return (this[field] = ffi);
 | |
|         }
 | |
|         return undefined;
 | |
|       },
 | |
|       configurable: true,
 | |
|       enumerable: true,
 | |
|     });
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * Define a js-ctypes function lazily using ctypes method declare.
 | |
|    *
 | |
|    * @param {object} The object containing the function as a field.
 | |
|    * @param {string} The name of the field containing the function.
 | |
|    * @param {string} symbol The name of the function, as defined in the
 | |
|    * library.
 | |
|    * @param {ctypes.abi} abi The abi to use, or |null| for default.
 | |
|    * @param {ctypes.CType} returnType The type of values returned by the function.
 | |
|    * @param {...ctypes.CType} argTypes The type of arguments to the function.
 | |
|    */
 | |
|   declareLazy(object, field, ...args) {
 | |
|     let lib = this;
 | |
|     Object.defineProperty(object, field, {
 | |
|       get() {
 | |
|         delete this[field];
 | |
|         let ffi = lib.library.declare(...args);
 | |
|         if (ffi) {
 | |
|           return (this[field] = ffi);
 | |
|         }
 | |
|         return undefined;
 | |
|       },
 | |
|       configurable: true,
 | |
|       enumerable: true,
 | |
|     });
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * Define a js-ctypes function lazily using ctypes method declare,
 | |
|    * with a fallback library to use if this library can't be opened
 | |
|    * or the function cannot be declared.
 | |
|    *
 | |
|    * @param {fallbacklibrary} The fallback Library object.
 | |
|    * @param {object} The object containing the function as a field.
 | |
|    * @param {string} The name of the field containing the function.
 | |
|    * @param {string} symbol The name of the function, as defined in the
 | |
|    * library.
 | |
|    * @param {ctypes.abi} abi The abi to use, or |null| for default.
 | |
|    * @param {ctypes.CType} returnType The type of values returned by the function.
 | |
|    * @param {...ctypes.CType} argTypes The type of arguments to the function.
 | |
|    */
 | |
|   declareLazyWithFallback(fallbacklibrary, object, field, ...args) {
 | |
|     let lib = this;
 | |
|     Object.defineProperty(object, field, {
 | |
|       get() {
 | |
|         delete this[field];
 | |
|         try {
 | |
|           let ffi = lib.library.declare(...args);
 | |
|           if (ffi) {
 | |
|             return (this[field] = ffi);
 | |
|           }
 | |
|         } catch (ex) {
 | |
|           // Use the fallback library and get the symbol from there.
 | |
|           fallbacklibrary.declareLazy(object, field, ...args);
 | |
|           return object[field];
 | |
|         }
 | |
|         return undefined;
 | |
|       },
 | |
|       configurable: true,
 | |
|       enumerable: true,
 | |
|     });
 | |
|   },
 | |
| 
 | |
|   toString() {
 | |
|     return "[Library " + this.name + "]";
 | |
|   },
 | |
| });
 | |
| exports.Library = Library;
 | |
| 
 | |
| /**
 | |
|  * Declare a function through js-ctypes
 | |
|  *
 | |
|  * @param {ctypes.library} lib The ctypes library holding the function.
 | |
|  * @param {string} symbol The name of the function, as defined in the
 | |
|  * library.
 | |
|  * @param {ctypes.abi} abi The abi to use, or |null| for default.
 | |
|  * @param {Type} returnType The type of values returned by the function.
 | |
|  * @param {...Type} argTypes The type of arguments to the function.
 | |
|  *
 | |
|  * @return null if the function could not be defined (generally because
 | |
|  * it does not exist), or a JavaScript wrapper performing the call to C
 | |
|  * and any type conversion required.
 | |
|  */
 | |
| var declareFFI = function declareFFI(
 | |
|   lib,
 | |
|   symbol,
 | |
|   abi,
 | |
|   returnType /* , argTypes ...*/
 | |
| ) {
 | |
|   LOG("Attempting to declare FFI ", symbol);
 | |
|   // We guard agressively, to avoid any late surprise
 | |
|   if (typeof symbol != "string") {
 | |
|     throw new TypeError("declareFFI expects as first argument a string");
 | |
|   }
 | |
|   abi = abi || ctypes.default_abi;
 | |
|   if (Object.prototype.toString.call(abi) != "[object CABI]") {
 | |
|     // Note: This is the only known manner of checking whether an object
 | |
|     // is an abi.
 | |
|     throw new TypeError("declareFFI expects as second argument an abi or null");
 | |
|   }
 | |
|   if (!returnType.importFromC) {
 | |
|     throw new TypeError(
 | |
|       "declareFFI expects as third argument an instance of Type"
 | |
|     );
 | |
|   }
 | |
|   let signature = [symbol, abi];
 | |
|   for (let i = 3; i < arguments.length; ++i) {
 | |
|     let current = arguments[i];
 | |
|     if (!current) {
 | |
|       throw new TypeError(
 | |
|         "Missing type for argument " + (i - 3) + " of symbol " + symbol
 | |
|       );
 | |
|     }
 | |
|     // Ellipsis for variadic arguments.
 | |
|     if (current == "...") {
 | |
|       if (i != arguments.length - 1) {
 | |
|         throw new TypeError("Variadic ellipsis must be the last argument");
 | |
|       }
 | |
|       signature.push(current);
 | |
|       continue;
 | |
|     }
 | |
|     if (!current.implementation) {
 | |
|       throw new TypeError(
 | |
|         "Missing implementation for argument " +
 | |
|           (i - 3) +
 | |
|           " of symbol " +
 | |
|           symbol +
 | |
|           " ( " +
 | |
|           current.name +
 | |
|           " )"
 | |
|       );
 | |
|     }
 | |
|     signature.push(current.implementation);
 | |
|   }
 | |
|   try {
 | |
|     let fun = lib.declare.apply(lib, signature);
 | |
|     let result = function ffi(...args) {
 | |
|       for (let i = 0; i < args.length; i++) {
 | |
|         if (typeof args[i] == "undefined") {
 | |
|           throw new TypeError(
 | |
|             "Argument " + i + " of " + symbol + " is undefined"
 | |
|           );
 | |
|         }
 | |
|       }
 | |
|       let result = fun.apply(fun, args);
 | |
|       return returnType.importFromC(result, symbol);
 | |
|     };
 | |
|     LOG("Function", symbol, "declared");
 | |
|     return result;
 | |
|   } catch (x) {
 | |
|     // Note: Not being able to declare a function is normal.
 | |
|     // Some functions are OS (or OS version)-specific.
 | |
|     LOG("Could not declare function ", symbol, x);
 | |
|     return null;
 | |
|   }
 | |
| };
 | |
| exports.declareFFI = declareFFI;
 | |
| 
 | |
| /**
 | |
|  * Define a lazy getter to a js-ctypes function using declareFFI.
 | |
|  *
 | |
|  * @param {object} The object containing the function as a field.
 | |
|  * @param {string} The name of the field containing the function.
 | |
|  * @param {ctypes.library} lib The ctypes library holding the function.
 | |
|  * @param {string} symbol The name of the function, as defined in the
 | |
|  * library.
 | |
|  * @param {ctypes.abi} abi The abi to use, or |null| for default.
 | |
|  * @param {Type} returnType The type of values returned by the function.
 | |
|  * @param {...Type} argTypes The type of arguments to the function.
 | |
|  */
 | |
| function declareLazyFFI(object, field, ...declareFFIArgs) {
 | |
|   Object.defineProperty(object, field, {
 | |
|     get() {
 | |
|       delete this[field];
 | |
|       let ffi = declareFFI(...declareFFIArgs);
 | |
|       if (ffi) {
 | |
|         return (this[field] = ffi);
 | |
|       }
 | |
|       return undefined;
 | |
|     },
 | |
|     configurable: true,
 | |
|     enumerable: true,
 | |
|   });
 | |
| }
 | |
| exports.declareLazyFFI = declareLazyFFI;
 | |
| 
 | |
| /**
 | |
|  * Define a lazy getter to a js-ctypes function using ctypes method declare.
 | |
|  *
 | |
|  * @param {object} The object containing the function as a field.
 | |
|  * @param {string} The name of the field containing the function.
 | |
|  * @param {ctypes.library} lib The ctypes library holding the function.
 | |
|  * @param {string} symbol The name of the function, as defined in the
 | |
|  * library.
 | |
|  * @param {ctypes.abi} abi The abi to use, or |null| for default.
 | |
|  * @param {ctypes.CType} returnType The type of values returned by the function.
 | |
|  * @param {...ctypes.CType} argTypes The type of arguments to the function.
 | |
|  */
 | |
| function declareLazy(object, field, lib, ...declareArgs) {
 | |
|   Object.defineProperty(object, field, {
 | |
|     get() {
 | |
|       delete this[field];
 | |
|       try {
 | |
|         let ffi = lib.declare(...declareArgs);
 | |
|         return (this[field] = ffi);
 | |
|       } catch (ex) {
 | |
|         // The symbol doesn't exist
 | |
|         return undefined;
 | |
|       }
 | |
|     },
 | |
|     configurable: true,
 | |
|   });
 | |
| }
 | |
| exports.declareLazy = declareLazy;
 | |
| 
 | |
| /**
 | |
|  * Utility function used to sanity check buffer and length arguments.  The
 | |
|  * buffer must be a Typed Array.
 | |
|  *
 | |
|  * @param {Typed array} candidate The buffer.
 | |
|  * @param {number} bytes The number of bytes that |candidate| should contain.
 | |
|  *
 | |
|  * @return number The bytes argument clamped to the length of the buffer.
 | |
|  */
 | |
| function normalizeBufferArgs(candidate, bytes) {
 | |
|   if (!candidate) {
 | |
|     throw new TypeError("Expecting a Typed Array");
 | |
|   }
 | |
|   if (!isTypedArray(candidate)) {
 | |
|     throw new TypeError("Expecting a Typed Array");
 | |
|   }
 | |
|   if (bytes == null) {
 | |
|     bytes = candidate.byteLength;
 | |
|   } else if (candidate.byteLength < bytes) {
 | |
|     throw new TypeError(
 | |
|       "Buffer is too short. I need at least " +
 | |
|         bytes +
 | |
|         " bytes but I have only " +
 | |
|         candidate.byteLength +
 | |
|         "bytes"
 | |
|     );
 | |
|   }
 | |
|   return bytes;
 | |
| }
 | |
| exports.normalizeBufferArgs = normalizeBufferArgs;
 | |
| 
 | |
| // /////////////////// OS interactions
 | |
| 
 | |
| /**
 | |
|  * An OS error.
 | |
|  *
 | |
|  * This class is provided mostly for type-matching. If you need more
 | |
|  * details about an error, you should use the platform-specific error
 | |
|  * codes provided by subclasses of |OS.Shared.Error|.
 | |
|  *
 | |
|  * @param {string} operation The operation that failed.
 | |
|  * @param {string=} path The path of the file on which the operation failed,
 | |
|  * or nothing if there was no file involved in the failure.
 | |
|  *
 | |
|  * @constructor
 | |
|  */
 | |
| function OSError(operation, path = "") {
 | |
|   Error.call(this);
 | |
|   this.operation = operation;
 | |
|   this.path = path;
 | |
| }
 | |
| OSError.prototype = Object.create(Error.prototype);
 | |
| exports.OSError = OSError;
 | |
| 
 | |
| // /////////////////// Temporary boilerplate
 | |
| // Boilerplate, to simplify the transition to require()
 | |
| // Do not rely upon this symbol, it will disappear with
 | |
| // bug 883050.
 | |
| exports.OS = {
 | |
|   Constants: exports.Constants,
 | |
|   Shared: {
 | |
|     LOG,
 | |
|     clone,
 | |
|     Type,
 | |
|     HollowStructure,
 | |
|     Error: OSError,
 | |
|     declareFFI,
 | |
|     projectValue,
 | |
|     isTypedArray,
 | |
|     defineLazyGetter,
 | |
|   },
 | |
| };
 | |
| 
 | |
| Object.defineProperty(exports.OS.Shared, "DEBUG", {
 | |
|   get() {
 | |
|     return Config.DEBUG;
 | |
|   },
 | |
|   set(x) {
 | |
|     Config.DEBUG = x;
 | |
|   },
 | |
| });
 | |
| Object.defineProperty(exports.OS.Shared, "TEST", {
 | |
|   get() {
 | |
|     return Config.TEST;
 | |
|   },
 | |
|   set(x) {
 | |
|     Config.TEST = x;
 | |
|   },
 | |
| });
 | |
| 
 | |
| // /////////////////// Permanent boilerplate
 | |
| if (typeof Components != "undefined") {
 | |
|   // eslint-disable-next-line mozilla/reject-global-this
 | |
|   this.EXPORTED_SYMBOLS = EXPORTED_SYMBOLS;
 | |
|   for (let symbol of EXPORTED_SYMBOLS) {
 | |
|     // eslint-disable-next-line mozilla/reject-global-this
 | |
|     this[symbol] = exports[symbol];
 | |
|   }
 | |
| }
 | 
