diff --git a/toolkit/components/osfile/osfile_shared_allthreads.jsm b/toolkit/components/osfile/osfile_shared_allthreads.jsm index 5f239ef5cbbf..54498bb25f4e 100644 --- a/toolkit/components/osfile/osfile_shared_allthreads.jsm +++ b/toolkit/components/osfile/osfile_shared_allthreads.jsm @@ -118,8 +118,10 @@ */ get in_ptr() { delete this.in_ptr; - let ptr_t = new PtrType("[in] " + this.name + "*", - this.implementation.ptr); + let ptr_t = new PtrType( + "[in] " + this.name + "*", + this.implementation.ptr, + this); Object.defineProperty(this, "in_ptr", { get: function() { @@ -134,8 +136,10 @@ */ get out_ptr() { delete this.out_ptr; - let ptr_t = new PtrType("[out] " + this.name + "*", - this.implementation.ptr); + let ptr_t = new PtrType( + "[out] " + this.name + "*", + this.implementation.ptr, + this); Object.defineProperty(this, "out_ptr", { get: function() { @@ -154,8 +158,10 @@ */ get inout_ptr() { delete this.inout_ptr; - let ptr_t = new PtrType("[inout] " + this.name + "*", - this.implementation.ptr); + let ptr_t = new PtrType( + "[inout] " + this.name + "*", + this.implementation.ptr, + this); Object.defineProperty(this, "inout_ptr", { get: function() { @@ -193,7 +199,17 @@ */ 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; + } }; @@ -202,9 +218,19 @@ * * @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) { + 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); @@ -371,7 +397,8 @@ */ Types.voidptr_t = new PtrType("void*", - ctypes.voidptr_t); + ctypes.voidptr_t, + Types.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 @@ -765,7 +792,50 @@ exports.OS.Shared.Utils = {}; let Strings = exports.OS.Shared.Utils.Strings = {}; - let Pointers = exports.OS.Shared.Utils.Pointers = {}; + + // A bogus array type used to perform pointer arithmetics + let gOffsetByType; + + /** + * Advance a pointer by a number of items. + * + * This method implements adding an integer to a pointer in C. + * + * Example: + * // ptr is a uint16_t*, + * offsetBy(ptr, 3) + * // returns a uint16_t* with the address ptr + 3 * 2 bytes + * + * @param {C pointer} pointer The start pointer. + * @param {number} length The number of items to advance. Must not be + * negative. + * + * @return {C pointer} |pointer| advanced by |length| items + */ + exports.OS.Shared.offsetBy = + function offsetBy(pointer, length) { + if (length === undefined || length < 0) { + throw new TypeError("offsetBy expects a positive number"); + } + if (!("isNull" in pointer)) { + throw new TypeError("offsetBy expects a pointer"); + } + if (length == 0) { + return pointer; + } + let type = pointer.constructor; + let size = type.targetType.size; + if (size == 0 || size == null) { + throw new TypeError("offsetBy cannot be applied to a pointer without size"); + } + let bytes = length * size; + if (!gOffsetByType || gOffsetByType.size <= bytes) { + gOffsetByType = ctypes.uint8_t.array(bytes * 2); + } + let addr = ctypes.cast(pointer, gOffsetByType.ptr). + contents.addressOfElement(bytes); + return ctypes.cast(addr, type); + }; /** * Import a wide string (e.g. a |jschar.ptr|) as a string. @@ -824,9 +894,6 @@ return Strings.importWString(decoded); }; - exports.OS.Shared.Utils = { Strings: Strings }; - - /** * Specific tools that don't really fit anywhere. */