12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463 |
- var assert = require('assert')
- var inspect = require('util').inspect
- var debug = require('debug')('ref')
- exports = module.exports = require('bindings')('binding')
- /**
- * A `Buffer` that references the C NULL pointer. That is, its memory address
- * points to 0. Its `length` is 0 because accessing any data from this buffer
- * would cause a _segmentation fault_.
- *
- * ```
- * console.log(ref.NULL);
- * <SlowBuffer@0x0 >
- * ```
- *
- * @name NULL
- * @type Buffer
- */
- /**
- * A string that represents the native endianness of the machine's processor.
- * The possible values are either `"LE"` or `"BE"`.
- *
- * ```
- * console.log(ref.endianness);
- * 'LE'
- * ```
- *
- * @name endianness
- * @type String
- */
- /**
- * Accepts a `Buffer` instance and returns the memory address of the buffer
- * instance.
- *
- * ```
- * console.log(ref.address(new Buffer(1)));
- * 4320233616
- *
- * console.log(ref.address(ref.NULL)));
- * 0
- * ```
- *
- * @param {Buffer} buffer The buffer to get the memory address of.
- * @return {Number} The memory address the buffer instance.
- * @name address
- * @type method
- */
- /**
- * Accepts a `Buffer` instance and returns _true_ if the buffer represents the
- * NULL pointer, _false_ otherwise.
- *
- * ```
- * console.log(ref.isNull(new Buffer(1)));
- * false
- *
- * console.log(ref.isNull(ref.NULL));
- * true
- * ```
- *
- * @param {Buffer} buffer The buffer to check for NULL.
- * @return {Boolean} true or false.
- * @name isNull
- * @type method
- */
- /**
- * Reads a JavaScript Object that has previously been written to the given
- * _buffer_ at the given _offset_.
- *
- * ```
- * var obj = { foo: 'bar' };
- * var buf = ref.alloc('Object', obj);
- *
- * var obj2 = ref.readObject(buf, 0);
- * console.log(obj === obj2);
- * true
- * ```
- *
- * @param {Buffer} buffer The buffer to read an Object from.
- * @param {Number} offset The offset to begin reading from.
- * @return {Object} The Object that was read from _buffer_.
- * @name readObject
- * @type method
- */
- /**
- * Reads a Buffer instance from the given _buffer_ at the given _offset_.
- * The _size_ parameter specifies the `length` of the returned Buffer instance,
- * which defaults to __0__.
- *
- * ```
- * var buf = new Buffer('hello world');
- * var pointer = ref.alloc('pointer');
- *
- * var buf2 = ref.readPointer(pointer, 0, buf.length);
- * console.log(buf.toString());
- * 'hello world'
- * ```
- *
- * @param {Buffer} buffer The buffer to read a Buffer from.
- * @param {Number} offset The offset to begin reading from.
- * @param {Number} length (optional) The length of the returned Buffer. Defaults to 0.
- * @return {Buffer} The Buffer instance that was read from _buffer_.
- * @name readPointer
- * @type method
- */
- /**
- * Returns a JavaScript String read from _buffer_ at the given _offset_. The
- * C String is read until the first NULL byte, which indicates the end of the
- * String.
- *
- * This function can read beyond the `length` of a Buffer.
- *
- * ```
- * var buf = new Buffer('hello\0world\0');
- *
- * var str = ref.readCString(buf, 0);
- * console.log(str);
- * 'hello'
- * ```
- *
- * @param {Buffer} buffer The buffer to read a Buffer from.
- * @param {Number} offset The offset to begin reading from.
- * @return {String} The String that was read from _buffer_.
- * @name readCString
- * @type method
- */
- /**
- * Returns a big-endian signed 64-bit int read from _buffer_ at the given
- * _offset_.
- *
- * If the returned value will fit inside a JavaScript Number without losing
- * precision, then a Number is returned, otherwise a String is returned.
- *
- * ```
- * var buf = ref.alloc('int64');
- * ref.writeInt64BE(buf, 0, '9223372036854775807');
- *
- * var val = ref.readInt64BE(buf, 0)
- * console.log(val)
- * '9223372036854775807'
- * ```
- *
- * @param {Buffer} buffer The buffer to read a Buffer from.
- * @param {Number} offset The offset to begin reading from.
- * @return {Number|String} The Number or String that was read from _buffer_.
- * @name readInt64BE
- * @type method
- */
- /**
- * Returns a little-endian signed 64-bit int read from _buffer_ at the given
- * _offset_.
- *
- * If the returned value will fit inside a JavaScript Number without losing
- * precision, then a Number is returned, otherwise a String is returned.
- *
- * ```
- * var buf = ref.alloc('int64');
- * ref.writeInt64LE(buf, 0, '9223372036854775807');
- *
- * var val = ref.readInt64LE(buf, 0)
- * console.log(val)
- * '9223372036854775807'
- * ```
- *
- * @param {Buffer} buffer The buffer to read a Buffer from.
- * @param {Number} offset The offset to begin reading from.
- * @return {Number|String} The Number or String that was read from _buffer_.
- * @name readInt64LE
- * @type method
- */
- /**
- * Returns a big-endian unsigned 64-bit int read from _buffer_ at the given
- * _offset_.
- *
- * If the returned value will fit inside a JavaScript Number without losing
- * precision, then a Number is returned, otherwise a String is returned.
- *
- * ```
- * var buf = ref.alloc('uint64');
- * ref.writeUInt64BE(buf, 0, '18446744073709551615');
- *
- * var val = ref.readUInt64BE(buf, 0)
- * console.log(val)
- * '18446744073709551615'
- * ```
- *
- * @param {Buffer} buffer The buffer to read a Buffer from.
- * @param {Number} offset The offset to begin reading from.
- * @return {Number|String} The Number or String that was read from _buffer_.
- * @name readUInt64BE
- * @type method
- */
- /**
- * Returns a little-endian unsigned 64-bit int read from _buffer_ at the given
- * _offset_.
- *
- * If the returned value will fit inside a JavaScript Number without losing
- * precision, then a Number is returned, otherwise a String is returned.
- *
- * ```
- * var buf = ref.alloc('uint64');
- * ref.writeUInt64LE(buf, 0, '18446744073709551615');
- *
- * var val = ref.readUInt64LE(buf, 0)
- * console.log(val)
- * '18446744073709551615'
- * ```
- *
- * @param {Buffer} buffer The buffer to read a Buffer from.
- * @param {Number} offset The offset to begin reading from.
- * @return {Number|String} The Number or String that was read from _buffer_.
- * @name readUInt64LE
- * @type method
- */
- /**
- * Writes the _input_ Number or String as a big-endian signed 64-bit int into
- * _buffer_ at the given _offset_.
- *
- * ```
- * var buf = ref.alloc('int64');
- * ref.writeInt64BE(buf, 0, '9223372036854775807');
- * ```
- *
- * @param {Buffer} buffer The buffer to write to.
- * @param {Number} offset The offset to begin writing from.
- * @param {Number|String} input This String or Number which gets written.
- * @name writeInt64BE
- * @type method
- */
- /**
- * Writes the _input_ Number or String as a little-endian signed 64-bit int into
- * _buffer_ at the given _offset_.
- *
- * ```
- * var buf = ref.alloc('int64');
- * ref.writeInt64LE(buf, 0, '9223372036854775807');
- * ```
- *
- * @param {Buffer} buffer The buffer to write to.
- * @param {Number} offset The offset to begin writing from.
- * @param {Number|String} input This String or Number which gets written.
- * @name writeInt64LE
- * @type method
- */
- /**
- * Writes the _input_ Number or String as a big-endian unsigned 64-bit int into
- * _buffer_ at the given _offset_.
- *
- * ```
- * var buf = ref.alloc('uint64');
- * ref.writeUInt64BE(buf, 0, '18446744073709551615');
- * ```
- *
- * @param {Buffer} buffer The buffer to write to.
- * @param {Number} offset The offset to begin writing from.
- * @param {Number|String} input This String or Number which gets written.
- * @name writeUInt64BE
- * @type method
- */
- /**
- * Writes the _input_ Number or String as a little-endian unsigned 64-bit int
- * into _buffer_ at the given _offset_.
- *
- * ```
- * var buf = ref.alloc('uint64');
- * ref.writeUInt64LE(buf, 0, '18446744073709551615');
- * ```
- *
- * @param {Buffer} buffer The buffer to write to.
- * @param {Number} offset The offset to begin writing from.
- * @param {Number|String} input This String or Number which gets written.
- * @name writeUInt64LE
- * @type method
- */
- /**
- * Returns a new clone of the given "type" object, with its
- * `indirection` level incremented by **1**.
- *
- * Say you wanted to create a type representing a `void *`:
- *
- * ```
- * var voidPtrType = ref.refType(ref.types.void);
- * ```
- *
- * @param {Object|String} type The "type" object to create a reference type from. Strings get coerced first.
- * @return {Object} The new "type" object with its `indirection` incremented by 1.
- */
- exports.refType = function refType (type) {
- var _type = exports.coerceType(type)
- var rtn = Object.create(_type)
- rtn.indirection++
- if (_type.name) {
- Object.defineProperty(rtn, 'name', {
- value: _type.name + '*',
- configurable: true,
- enumerable: true,
- writable: true
- })
- }
- return rtn
- }
- /**
- * Returns a new clone of the given "type" object, with its
- * `indirection` level decremented by 1.
- *
- * @param {Object|String} type The "type" object to create a dereference type from. Strings get coerced first.
- * @return {Object} The new "type" object with its `indirection` decremented by 1.
- */
- exports.derefType = function derefType (type) {
- var _type = exports.coerceType(type)
- if (_type.indirection === 1) {
- throw new Error('Cannot create deref\'d type for type with indirection 1')
- }
- var rtn = Object.getPrototypeOf(_type)
- if (rtn.indirection !== _type.indirection - 1) {
- // slow case
- rtn = Object.create(_type)
- rtn.indirection--
- }
- return rtn
- }
- /**
- * Coerces a "type" object from a String or an actual "type" object. String values
- * are looked up from the `ref.types` Object. So:
- *
- * * `"int"` gets coerced into `ref.types.int`.
- * * `"int *"` gets translated into `ref.refType(ref.types.int)`
- * * `ref.types.int` gets translated into `ref.types.int` (returns itself)
- *
- * Throws an Error if no valid "type" object could be determined. Most `ref`
- * functions use this function under the hood, so anywhere a "type" object is
- * expected, a String may be passed as well, including simply setting the
- * `buffer.type` property.
- *
- * ```
- * var type = ref.coerceType('int **');
- *
- * console.log(type.indirection);
- * 3
- * ```
- *
- * @param {Object|String} type The "type" Object or String to coerce.
- * @return {Object} A "type" object
- */
- exports.coerceType = function coerceType (type) {
- var rtn = type
- if (typeof rtn === 'string') {
- rtn = exports.types[type]
- if (rtn) return rtn
- // strip whitespace
- rtn = type.replace(/\s+/g, '').toLowerCase()
- if (rtn === 'pointer') {
- // legacy "pointer" being used :(
- rtn = exports.refType(exports.types.void) // void *
- } else if (rtn === 'string') {
- rtn = exports.types.CString // special char * type
- } else {
- var refCount = 0
- rtn = rtn.replace(/\*/g, function () {
- refCount++
- return ''
- })
- // allow string names to be passed in
- rtn = exports.types[rtn]
- if (refCount > 0) {
- if (!(rtn && 'size' in rtn && 'indirection' in rtn)) {
- throw new TypeError('could not determine a proper "type" from: ' + JSON.stringify(type))
- }
- for (var i = 0; i < refCount; i++) {
- rtn = exports.refType(rtn)
- }
- }
- }
- }
- if (!(rtn && 'size' in rtn && 'indirection' in rtn)) {
- throw new TypeError('could not determine a proper "type" from: ' + JSON.stringify(type))
- }
- return rtn
- }
- /**
- * Returns the "type" property of the given Buffer.
- * Creates a default type for the buffer when none exists.
- *
- * @param {Buffer} buffer The Buffer instance to get the "type" object from.
- * @return {Object} The "type" object from the given Buffer.
- */
- exports.getType = function getType (buffer) {
- if (!buffer.type) {
- debug('WARN: no "type" found on buffer, setting default "type"', buffer)
- buffer.type = {}
- buffer.type.size = buffer.length
- buffer.type.indirection = 1
- buffer.type.get = function get () {
- throw new Error('unknown "type"; cannot get()')
- }
- buffer.type.set = function set () {
- throw new Error('unknown "type"; cannot set()')
- }
- }
- return exports.coerceType(buffer.type)
- }
- /**
- * Calls the `get()` function of the Buffer's current "type" (or the
- * passed in _type_ if present) at the given _offset_.
- *
- * This function handles checking the "indirection" level and returning a
- * proper "dereferenced" Bufffer instance when necessary.
- *
- * @param {Buffer} buffer The Buffer instance to read from.
- * @param {Number} offset (optional) The offset on the Buffer to start reading from. Defaults to 0.
- * @param {Object|String} type (optional) The "type" object to use when reading. Defaults to calling `getType()` on the buffer.
- * @return {?} Whatever value the "type" used when reading returns.
- */
- exports.get = function get (buffer, offset, type) {
- if (!offset) {
- offset = 0
- }
- if (type) {
- type = exports.coerceType(type)
- } else {
- type = exports.getType(buffer)
- }
- debug('get(): (offset: %d)', offset, buffer)
- assert(type.indirection > 0, '"indirection" level must be at least 1')
- if (type.indirection === 1) {
- // need to check "type"
- return type.get(buffer, offset)
- } else {
- // need to create a deref'd Buffer
- var size = type.indirection === 2 ? type.size : exports.sizeof.pointer
- var reference = exports.readPointer(buffer, offset, size)
- reference.type = exports.derefType(type)
- return reference
- }
- }
- /**
- * Calls the `set()` function of the Buffer's current "type" (or the
- * passed in _type_ if present) at the given _offset_.
- *
- * This function handles checking the "indirection" level writing a pointer rather
- * than calling the `set()` function if the indirection is greater than 1.
- *
- * @param {Buffer} buffer The Buffer instance to write to.
- * @param {Number} offset The offset on the Buffer to start writing to.
- * @param {?} value The value to write to the Buffer instance.
- * @param {Object|String} type (optional) The "type" object to use when reading. Defaults to calling `getType()` on the buffer.
- */
- exports.set = function set (buffer, offset, value, type) {
- if (!offset) {
- offset = 0
- }
- if (type) {
- type = exports.coerceType(type)
- } else {
- type = exports.getType(buffer)
- }
- debug('set(): (offset: %d)', offset, buffer, value)
- assert(type.indirection >= 1, '"indirection" level must be at least 1')
- if (type.indirection === 1) {
- type.set(buffer, offset, value)
- } else {
- exports.writePointer(buffer, offset, value)
- }
- }
- /**
- * Returns a new Buffer instance big enough to hold `type`,
- * with the given `value` written to it.
- *
- * ``` js
- * var intBuf = ref.alloc(ref.types.int)
- * var int_with_4 = ref.alloc(ref.types.int, 4)
- * ```
- *
- * @param {Object|String} type The "type" object to allocate. Strings get coerced first.
- * @param {?} value (optional) The initial value set on the returned Buffer, using _type_'s `set()` function.
- * @return {Buffer} A new Buffer instance with it's `type` set to "type", and (optionally) "value" written to it.
- */
- exports.alloc = function alloc (_type, value) {
- var type = exports.coerceType(_type)
- debug('allocating Buffer for type with "size"', type.size)
- var size
- if (type.indirection === 1) {
- size = type.size
- } else {
- size = exports.sizeof.pointer
- }
- var buffer = new Buffer(size)
- buffer.type = type
- if (arguments.length >= 2) {
- debug('setting value on allocated buffer', value)
- exports.set(buffer, 0, value, type)
- }
- return buffer
- }
- /**
- * Returns a new `Buffer` instance with the given String written to it with the
- * given encoding (defaults to __'utf8'__). The buffer is 1 byte longer than the
- * string itself, and is NUL terminated.
- *
- * ```
- * var buf = ref.allocCString('hello world');
- *
- * console.log(buf.toString());
- * 'hello world\u0000'
- * ```
- *
- * @param {String} string The JavaScript string to be converted to a C string.
- * @param {String} encoding (optional) The encoding to use for the C string. Defaults to __'utf8'__.
- * @return {Buffer} The new `Buffer` instance with the specified String wrtten to it, and a trailing NUL byte.
- */
- exports.allocCString = function allocCString (string, encoding) {
- if (null == string || (Buffer.isBuffer(string) && exports.isNull(string))) {
- return exports.NULL
- }
- var size = Buffer.byteLength(string, encoding) + 1
- var buffer = new Buffer(size)
- exports.writeCString(buffer, 0, string, encoding)
- buffer.type = charPtrType
- return buffer
- }
- /**
- * Writes the given string as a C String (NULL terminated) to the given buffer
- * at the given offset. "encoding" is optional and defaults to __'utf8'__.
- *
- * Unlike `readCString()`, this function requires the buffer to actually have the
- * proper length.
- *
- * @param {Buffer} buffer The Buffer instance to write to.
- * @param {Number} offset The offset of the buffer to begin writing at.
- * @param {String} string The JavaScript String to write that will be written to the buffer.
- * @param {String} encoding (optional) The encoding to read the C string as. Defaults to __'utf8'__.
- */
- exports.writeCString = function writeCString (buffer, offset, string, encoding) {
- assert(Buffer.isBuffer(buffer), 'expected a Buffer as the first argument')
- assert.equal('string', typeof string, 'expected a "string" as the third argument')
- if (!offset) {
- offset = 0
- }
- if (!encoding) {
- encoding = 'utf8'
- }
- var size = buffer.length - offset
- var len = buffer.write(string, offset, size, encoding)
- buffer.writeUInt8(0, offset + len) // NUL terminate
- }
- exports['readInt64' + exports.endianness] = exports.readInt64
- exports['readUInt64' + exports.endianness] = exports.readUInt64
- exports['writeInt64' + exports.endianness] = exports.writeInt64
- exports['writeUInt64' + exports.endianness] = exports.writeUInt64
- var opposite = exports.endianness == 'LE' ? 'BE' : 'LE'
- var int64temp = new Buffer(exports.sizeof.int64)
- var uint64temp = new Buffer(exports.sizeof.uint64)
- exports['readInt64' + opposite] = function (buffer, offset) {
- for (var i = 0; i < exports.sizeof.int64; i++) {
- int64temp[i] = buffer[offset + exports.sizeof.int64 - i - 1]
- }
- return exports.readInt64(int64temp, 0)
- }
- exports['readUInt64' + opposite] = function (buffer, offset) {
- for (var i = 0; i < exports.sizeof.uint64; i++) {
- uint64temp[i] = buffer[offset + exports.sizeof.uint64 - i - 1]
- }
- return exports.readUInt64(uint64temp, 0)
- }
- exports['writeInt64' + opposite] = function (buffer, offset, value) {
- exports.writeInt64(int64temp, 0, value)
- for (var i = 0; i < exports.sizeof.int64; i++) {
- buffer[offset + i] = int64temp[exports.sizeof.int64 - i - 1]
- }
- }
- exports['writeUInt64' + opposite] = function (buffer, offset, value) {
- exports.writeUInt64(uint64temp, 0, value)
- for (var i = 0; i < exports.sizeof.uint64; i++) {
- buffer[offset + i] = uint64temp[exports.sizeof.uint64 - i - 1]
- }
- }
- /**
- * `ref()` accepts a Buffer instance and returns a new Buffer
- * instance that is "pointer" sized and has its data pointing to the given
- * Buffer instance. Essentially the created Buffer is a "reference" to the
- * original pointer, equivalent to the following C code:
- *
- * ``` c
- * char *buf = buffer;
- * char **ref = &buf;
- * ```
- *
- * @param {Buffer} buffer A Buffer instance to create a reference to.
- * @return {Buffer} A new Buffer instance pointing to _buffer_.
- */
- exports.ref = function ref (buffer) {
- debug('creating a reference to buffer', buffer)
- var type = exports.refType(exports.getType(buffer))
- return exports.alloc(type, buffer)
- }
- /**
- * Accepts a Buffer instance and attempts to "dereference" it.
- * That is, first it checks the `indirection` count of _buffer_'s "type", and if
- * it's greater than __1__ then it merely returns another Buffer, but with one
- * level less `indirection`.
- *
- * When _buffer_'s indirection is at __1__, then it checks for `buffer.type`
- * which should be an Object with its own `get()` function.
- *
- * ```
- * var buf = ref.alloc('int', 6);
- *
- * var val = ref.deref(buf);
- * console.log(val);
- * 6
- * ```
- *
- *
- * @param {Buffer} buffer A Buffer instance to dereference.
- * @return {?} The returned value after dereferencing _buffer_.
- */
- exports.deref = function deref (buffer) {
- debug('dereferencing buffer', buffer)
- return exports.get(buffer)
- }
- /**
- * Attaches _object_ to _buffer_ such that it prevents _object_ from being garbage
- * collected until _buffer_ does.
- *
- * @param {Buffer} buffer A Buffer instance to attach _object_ to.
- * @param {Object|Buffer} object An Object or Buffer to prevent from being garbage collected until _buffer_ does.
- * @api private
- */
- exports._attach = function _attach (buf, obj) {
- if (!buf._refs) {
- buf._refs = []
- }
- buf._refs.push(obj)
- }
- /**
- * Same as `ref.writeObject()`, except that this version does not _attach_ the
- * Object to the Buffer, which is potentially unsafe if the garbage collector
- * runs.
- *
- * @param {Buffer} buffer A Buffer instance to write _object_ to.
- * @param {Number} offset The offset on the Buffer to start writing at.
- * @param {Object} object The Object to be written into _buffer_.
- * @api private
- */
- exports._writeObject = exports.writeObject
- /**
- * Writes a pointer to _object_ into _buffer_ at the specified _offset.
- *
- * This function "attaches" _object_ to _buffer_ to prevent it from being garbage
- * collected.
- *
- * ```
- * var buf = ref.alloc('Object');
- * ref.writeObject(buf, 0, { foo: 'bar' });
- *
- * ```
- *
- * @param {Buffer} buffer A Buffer instance to write _object_ to.
- * @param {Number} offset The offset on the Buffer to start writing at.
- * @param {Object} object The Object to be written into _buffer_.
- */
- exports.writeObject = function writeObject (buf, offset, obj, persistent) {
- debug('writing Object to buffer', buf, offset, obj, persistent)
- exports._writeObject(buf, offset, obj, persistent)
- exports._attach(buf, obj)
- }
- /**
- * Same as `ref.writePointer()`, except that this version does not attach
- * _pointer_ to _buffer_, which is potentially unsafe if the garbage collector
- * runs.
- *
- * @param {Buffer} buffer A Buffer instance to write _pointer to.
- * @param {Number} offset The offset on the Buffer to start writing at.
- * @param {Buffer} pointer The Buffer instance whose memory address will be written to _buffer_.
- * @api private
- */
- exports._writePointer = exports.writePointer
- /**
- * Writes the memory address of _pointer_ to _buffer_ at the specified _offset_.
- *
- * This function "attaches" _object_ to _buffer_ to prevent it from being garbage
- * collected.
- *
- * ```
- * var someBuffer = new Buffer('whatever');
- * var buf = ref.alloc('pointer');
- * ref.writePointer(buf, 0, someBuffer);
- * ```
- *
- * @param {Buffer} buffer A Buffer instance to write _pointer to.
- * @param {Number} offset The offset on the Buffer to start writing at.
- * @param {Buffer} pointer The Buffer instance whose memory address will be written to _buffer_.
- */
- exports.writePointer = function writePointer (buf, offset, ptr) {
- debug('writing pointer to buffer', buf, offset, ptr)
- exports._writePointer(buf, offset, ptr)
- exports._attach(buf, ptr)
- }
- /**
- * Same as `ref.reinterpret()`, except that this version does not attach
- * _buffer_ to the returned Buffer, which is potentially unsafe if the
- * garbage collector runs.
- *
- * @param {Buffer} buffer A Buffer instance to base the returned Buffer off of.
- * @param {Number} size The `length` property of the returned Buffer.
- * @param {Number} offset The offset of the Buffer to begin from.
- * @return {Buffer} A new Buffer instance with the same memory address as _buffer_, and the requested _size_.
- * @api private
- */
- exports._reinterpret = exports.reinterpret
- /**
- * Returns a new Buffer instance with the specified _size_, with the same memory
- * address as _buffer_.
- *
- * This function "attaches" _buffer_ to the returned Buffer to prevent it from
- * being garbage collected.
- *
- * @param {Buffer} buffer A Buffer instance to base the returned Buffer off of.
- * @param {Number} size The `length` property of the returned Buffer.
- * @param {Number} offset The offset of the Buffer to begin from.
- * @return {Buffer} A new Buffer instance with the same memory address as _buffer_, and the requested _size_.
- */
- exports.reinterpret = function reinterpret (buffer, size, offset) {
- debug('reinterpreting buffer to "%d" bytes', size)
- var rtn = exports._reinterpret(buffer, size, offset || 0)
- exports._attach(rtn, buffer)
- return rtn
- }
- /**
- * Same as `ref.reinterpretUntilZeros()`, except that this version does not
- * attach _buffer_ to the returned Buffer, which is potentially unsafe if the
- * garbage collector runs.
- *
- * @param {Buffer} buffer A Buffer instance to base the returned Buffer off of.
- * @param {Number} size The number of sequential, aligned `NULL` bytes that are required to terminate the buffer.
- * @param {Number} offset The offset of the Buffer to begin from.
- * @return {Buffer} A new Buffer instance with the same memory address as _buffer_, and a variable `length` that is terminated by _size_ NUL bytes.
- * @api private
- */
- exports._reinterpretUntilZeros = exports.reinterpretUntilZeros
- /**
- * Accepts a `Buffer` instance and a number of `NULL` bytes to read from the
- * pointer. This function will scan past the boundary of the Buffer's `length`
- * until it finds `size` number of aligned `NULL` bytes.
- *
- * This is useful for finding the end of NUL-termintated array or C string. For
- * example, the `readCString()` function _could_ be implemented like:
- *
- * ```
- * function readCString (buf) {
- * return ref.reinterpretUntilZeros(buf, 1).toString('utf8')
- * }
- * ```
- *
- * This function "attaches" _buffer_ to the returned Buffer to prevent it from
- * being garbage collected.
- *
- * @param {Buffer} buffer A Buffer instance to base the returned Buffer off of.
- * @param {Number} size The number of sequential, aligned `NULL` bytes are required to terminate the buffer.
- * @param {Number} offset The offset of the Buffer to begin from.
- * @return {Buffer} A new Buffer instance with the same memory address as _buffer_, and a variable `length` that is terminated by _size_ NUL bytes.
- */
- exports.reinterpretUntilZeros = function reinterpretUntilZeros (buffer, size, offset) {
- debug('reinterpreting buffer to until "%d" NULL (0) bytes are found', size)
- var rtn = exports._reinterpretUntilZeros(buffer, size, offset || 0)
- exports._attach(rtn, buffer)
- return rtn
- }
- // the built-in "types"
- var types = exports.types = {}
- /**
- * The `void` type.
- *
- * @section types
- */
- types.void = {
- size: 0
- , indirection: 1
- , get: function get (buf, offset) {
- debug('getting `void` type (returns `null`)')
- return null
- }
- , set: function set (buf, offset, val) {
- debug('setting `void` type (no-op)')
- }
- }
- /**
- * The `int8` type.
- */
- types.int8 = {
- size: exports.sizeof.int8
- , indirection: 1
- , get: function get (buf, offset) {
- return buf.readInt8(offset || 0)
- }
- , set: function set (buf, offset, val) {
- if (typeof val === 'string') {
- val = val.charCodeAt(0)
- }
- return buf.writeInt8(val, offset || 0)
- }
- }
- /**
- * The `uint8` type.
- */
- types.uint8 = {
- size: exports.sizeof.uint8
- , indirection: 1
- , get: function get (buf, offset) {
- return buf.readUInt8(offset || 0)
- }
- , set: function set (buf, offset, val) {
- if (typeof val === 'string') {
- val = val.charCodeAt(0)
- }
- return buf.writeUInt8(val, offset || 0)
- }
- }
- /**
- * The `int16` type.
- */
- types.int16 = {
- size: exports.sizeof.int16
- , indirection: 1
- , get: function get (buf, offset) {
- return buf['readInt16' + exports.endianness](offset || 0)
- }
- , set: function set (buf, offset, val) {
- return buf['writeInt16' + exports.endianness](val, offset || 0)
- }
- }
- /**
- * The `uint16` type.
- */
- types.uint16 = {
- size: exports.sizeof.uint16
- , indirection: 1
- , get: function get (buf, offset) {
- return buf['readUInt16' + exports.endianness](offset || 0)
- }
- , set: function set (buf, offset, val) {
- return buf['writeUInt16' + exports.endianness](val, offset || 0)
- }
- }
- /**
- * The `int32` type.
- */
- types.int32 = {
- size: exports.sizeof.int32
- , indirection: 1
- , get: function get (buf, offset) {
- return buf['readInt32' + exports.endianness](offset || 0)
- }
- , set: function set (buf, offset, val) {
- return buf['writeInt32' + exports.endianness](val, offset || 0)
- }
- }
- /**
- * The `uint32` type.
- */
- types.uint32 = {
- size: exports.sizeof.uint32
- , indirection: 1
- , get: function get (buf, offset) {
- return buf['readUInt32' + exports.endianness](offset || 0)
- }
- , set: function set (buf, offset, val) {
- return buf['writeUInt32' + exports.endianness](val, offset || 0)
- }
- }
- /**
- * The `int64` type.
- */
- types.int64 = {
- size: exports.sizeof.int64
- , indirection: 1
- , get: function get (buf, offset) {
- return buf['readInt64' + exports.endianness](offset || 0)
- }
- , set: function set (buf, offset, val) {
- return buf['writeInt64' + exports.endianness](val, offset || 0)
- }
- }
- /**
- * The `uint64` type.
- */
- types.uint64 = {
- size: exports.sizeof.uint64
- , indirection: 1
- , get: function get (buf, offset) {
- return buf['readUInt64' + exports.endianness](offset || 0)
- }
- , set: function set (buf, offset, val) {
- return buf['writeUInt64' + exports.endianness](val, offset || 0)
- }
- }
- /**
- * The `float` type.
- */
- types.float = {
- size: exports.sizeof.float
- , indirection: 1
- , get: function get (buf, offset) {
- return buf['readFloat' + exports.endianness](offset || 0)
- }
- , set: function set (buf, offset, val) {
- return buf['writeFloat' + exports.endianness](val, offset || 0)
- }
- }
- /**
- * The `double` type.
- */
- types.double = {
- size: exports.sizeof.double
- , indirection: 1
- , get: function get (buf, offset) {
- return buf['readDouble' + exports.endianness](offset || 0)
- }
- , set: function set (buf, offset, val) {
- return buf['writeDouble' + exports.endianness](val, offset || 0)
- }
- }
- /**
- * The `Object` type. This can be used to read/write regular JS Objects
- * into raw memory.
- */
- types.Object = {
- size: exports.sizeof.Object
- , indirection: 1
- , get: function get (buf, offset) {
- return buf.readObject(offset || 0)
- }
- , set: function set (buf, offset, val) {
- return buf.writeObject(val, offset || 0)
- }
- }
- /**
- * The `CString` (a.k.a `"string"`) type.
- *
- * CStrings are a kind of weird thing. We say it's `sizeof(char *)`, and
- * `indirection` level of 1, which means that we have to return a Buffer that
- * is pointer sized, and points to a some utf8 string data, so we have to create
- * a 2nd "in-between" buffer.
- */
- types.CString = {
- size: exports.sizeof.pointer
- , alignment: exports.alignof.pointer
- , indirection: 1
- , get: function get (buf, offset) {
- var _buf = exports.readPointer(buf, offset)
- if (exports.isNull(_buf)) {
- return null
- }
- return exports.readCString(_buf, 0)
- }
- , set: function set (buf, offset, val) {
- var _buf
- if (Buffer.isBuffer(val)) {
- _buf = val
- } else {
- // assume string
- _buf = exports.allocCString(val)
- }
- return exports.writePointer(buf, offset, _buf)
- }
- }
- // alias Utf8String
- var utfstringwarned = false
- Object.defineProperty(types, 'Utf8String', {
- enumerable: false
- , configurable: true
- , get: function () {
- if (!utfstringwarned) {
- utfstringwarned = true
- console.error('"Utf8String" type is deprecated, use "CString" instead')
- }
- return types.CString
- }
- })
- /**
- * The `bool` type.
- *
- * Wrapper type around `types.uint8` that accepts/returns `true` or
- * `false` Boolean JavaScript values.
- *
- * @name bool
- *
- */
- /**
- * The `byte` type.
- *
- * @name byte
- */
- /**
- * The `char` type.
- *
- * @name char
- */
- /**
- * The `uchar` type.
- *
- * @name uchar
- */
- /**
- * The `short` type.
- *
- * @name short
- */
- /**
- * The `ushort` type.
- *
- * @name ushort
- */
- /**
- * The `int` type.
- *
- * @name int
- */
- /**
- * The `uint` type.
- *
- * @name uint
- */
- /**
- * The `long` type.
- *
- * @name long
- */
- /**
- * The `ulong` type.
- *
- * @name ulong
- */
- /**
- * The `longlong` type.
- *
- * @name longlong
- */
- /**
- * The `ulonglong` type.
- *
- * @name ulonglong
- */
- /**
- * The `size_t` type.
- *
- * @name size_t
- */
- // "typedef"s for the variable-sized types
- ;[ 'bool', 'byte', 'char', 'uchar', 'short', 'ushort', 'int', 'uint', 'long'
- , 'ulong', 'longlong', 'ulonglong', 'size_t' ].forEach(function (name) {
- var unsigned = name === 'bool'
- || name === 'byte'
- || name === 'size_t'
- || name[0] === 'u'
- var size = exports.sizeof[name]
- assert(size >= 1 && size <= 8)
- var typeName = 'int' + (size * 8)
- if (unsigned) {
- typeName = 'u' + typeName
- }
- var type = exports.types[typeName]
- assert(type)
- exports.types[name] = Object.create(type)
- })
- // set the "alignment" property on the built-in types
- Object.keys(exports.alignof).forEach(function (name) {
- if (name === 'pointer') return
- exports.types[name].alignment = exports.alignof[name]
- assert(exports.types[name].alignment > 0)
- })
- // make the `bool` type work with JS true/false values
- exports.types.bool.get = (function (_get) {
- return function get (buf, offset) {
- return _get(buf, offset) ? true : false
- }
- })(exports.types.bool.get)
- exports.types.bool.set = (function (_set) {
- return function set (buf, offset, val) {
- if (typeof val !== 'number') {
- val = val ? 1 : 0
- }
- return _set(buf, offset, val)
- }
- })(exports.types.bool.set)
- /*!
- * Set the `name` property of the types. Used for debugging...
- */
- Object.keys(exports.types).forEach(function (name) {
- exports.types[name].name = name
- })
- /*!
- * This `char *` type is used by "allocCString()" above.
- */
- var charPtrType = exports.refType(exports.types.char)
- /*!
- * Set the `type` property of the `NULL` pointer Buffer object.
- */
- exports.NULL.type = exports.types.void
- /**
- * `NULL_POINTER` is a pointer-sized `Buffer` instance pointing to `NULL`.
- * Conceptually, it's equivalent to the following C code:
- *
- * ``` c
- * char *null_pointer;
- * null_pointer = NULL;
- * ```
- *
- * @type Buffer
- */
- exports.NULL_POINTER = exports.ref(exports.NULL)
- /**
- * All these '...' comment blocks below are for the documentation generator.
- *
- * @section buffer
- */
- Buffer.prototype.address = function address () {
- return exports.address(this, 0)
- }
- /**
- * ...
- */
- Buffer.prototype.hexAddress = function hexAddress () {
- return exports.hexAddress(this, 0)
- }
- /**
- * ...
- */
- Buffer.prototype.isNull = function isNull () {
- return exports.isNull(this, 0)
- }
- /**
- * ...
- */
- Buffer.prototype.ref = function ref () {
- return exports.ref(this)
- }
- /**
- * ...
- */
- Buffer.prototype.deref = function deref () {
- return exports.deref(this)
- }
- /**
- * ...
- */
- Buffer.prototype.readObject = function readObject (offset) {
- return exports.readObject(this, offset)
- }
- /**
- * ...
- */
- Buffer.prototype.writeObject = function writeObject (obj, offset) {
- return exports.writeObject(this, offset, obj)
- }
- /**
- * ...
- */
- Buffer.prototype.readPointer = function readPointer (offset, size) {
- return exports.readPointer(this, offset, size)
- }
- /**
- * ...
- */
- Buffer.prototype.writePointer = function writePointer (ptr, offset) {
- return exports.writePointer(this, offset, ptr)
- }
- /**
- * ...
- */
- Buffer.prototype.readCString = function readCString (offset) {
- return exports.readCString(this, offset)
- }
- /**
- * ...
- */
- Buffer.prototype.writeCString = function writeCString (string, offset, encoding) {
- return exports.writeCString(this, offset, string, encoding)
- }
- /**
- * ...
- */
- Buffer.prototype.readInt64BE = function readInt64BE (offset) {
- return exports.readInt64BE(this, offset)
- }
- /**
- * ...
- */
- Buffer.prototype.writeInt64BE = function writeInt64BE (val, offset) {
- return exports.writeInt64BE(this, offset, val)
- }
- /**
- * ...
- */
- Buffer.prototype.readUInt64BE = function readUInt64BE (offset) {
- return exports.readUInt64BE(this, offset)
- }
- /**
- * ...
- */
- Buffer.prototype.writeUInt64BE = function writeUInt64BE (val, offset) {
- return exports.writeUInt64BE(this, offset, val)
- }
- /**
- * ...
- */
- Buffer.prototype.readInt64LE = function readInt64LE (offset) {
- return exports.readInt64LE(this, offset)
- }
- /**
- * ...
- */
- Buffer.prototype.writeInt64LE = function writeInt64LE (val, offset) {
- return exports.writeInt64LE(this, offset, val)
- }
- /**
- * ...
- */
- Buffer.prototype.readUInt64LE = function readUInt64LE (offset) {
- return exports.readUInt64LE(this, offset)
- }
- /**
- * ...
- */
- Buffer.prototype.writeUInt64LE = function writeUInt64LE (val, offset) {
- return exports.writeUInt64LE(this, offset, val)
- }
- /**
- * ...
- */
- Buffer.prototype.reinterpret = function reinterpret (size, offset) {
- return exports.reinterpret(this, size, offset)
- }
- /**
- * ...
- */
- Buffer.prototype.reinterpretUntilZeros = function reinterpretUntilZeros (size, offset) {
- return exports.reinterpretUntilZeros(this, size, offset)
- }
- /**
- * `ref` overwrites the default `Buffer#inspect()` function to include the
- * hex-encoded memory address of the Buffer instance when invoked.
- *
- * This is simply a nice-to-have.
- *
- * **Before**:
- *
- * ``` js
- * console.log(new Buffer('ref'));
- * <Buffer 72 65 66>
- * ```
- *
- * **After**:
- *
- * ``` js
- * console.log(new Buffer('ref'));
- * <Buffer@0x103015490 72 65 66>
- * ```
- */
- var inspectSym = inspect.custom || 'inspect'
- Buffer.prototype[inspectSym] = overwriteInspect(Buffer.prototype[inspectSym])
- // does SlowBuffer inherit from Buffer? (node >= v0.7.9)
- if (!(exports.NULL instanceof Buffer)) {
- debug('extending SlowBuffer\'s prototype since it doesn\'t inherit from Buffer.prototype')
- /*!
- * SlowBuffer convenience methods.
- */
- var SlowBuffer = require('buffer').SlowBuffer
- SlowBuffer.prototype.address = Buffer.prototype.address
- SlowBuffer.prototype.hexAddress = Buffer.prototype.hexAddress
- SlowBuffer.prototype.isNull = Buffer.prototype.isNull
- SlowBuffer.prototype.ref = Buffer.prototype.ref
- SlowBuffer.prototype.deref = Buffer.prototype.deref
- SlowBuffer.prototype.readObject = Buffer.prototype.readObject
- SlowBuffer.prototype.writeObject = Buffer.prototype.writeObject
- SlowBuffer.prototype.readPointer = Buffer.prototype.readPointer
- SlowBuffer.prototype.writePointer = Buffer.prototype.writePointer
- SlowBuffer.prototype.readCString = Buffer.prototype.readCString
- SlowBuffer.prototype.writeCString = Buffer.prototype.writeCString
- SlowBuffer.prototype.reinterpret = Buffer.prototype.reinterpret
- SlowBuffer.prototype.reinterpretUntilZeros = Buffer.prototype.reinterpretUntilZeros
- SlowBuffer.prototype.readInt64BE = Buffer.prototype.readInt64BE
- SlowBuffer.prototype.writeInt64BE = Buffer.prototype.writeInt64BE
- SlowBuffer.prototype.readUInt64BE = Buffer.prototype.readUInt64BE
- SlowBuffer.prototype.writeUInt64BE = Buffer.prototype.writeUInt64BE
- SlowBuffer.prototype.readInt64LE = Buffer.prototype.readInt64LE
- SlowBuffer.prototype.writeInt64LE = Buffer.prototype.writeInt64LE
- SlowBuffer.prototype.readUInt64LE = Buffer.prototype.readUInt64LE
- SlowBuffer.prototype.writeUInt64LE = Buffer.prototype.writeUInt64LE
- SlowBuffer.prototype[inspectSym] = overwriteInspect(SlowBuffer.prototype[inspectSym])
- }
- function overwriteInspect (inspect) {
- if (inspect.name === 'refinspect') {
- return inspect
- } else {
- return function refinspect () {
- var v = inspect.apply(this, arguments)
- return v.replace('Buffer', 'Buffer@0x' + this.hexAddress())
- }
- }
- }
|