Launch Week Day 5: Introducing Reachability for PHP.Learn More
Socket
Book a DemoSign in
Socket

bencode

Package Overview
Dependencies
Maintainers
2
Versions
29
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

bencode - npm Package Compare versions

Comparing version
0.5.2
to
0.6.0
+12
benchmark/instanceof.js
var bfr = new Buffer(1)
var nobfr = []
suite('instanceof vs Buffer.isBuffer', function() {
bench('isBuffer', function() {
var x = Buffer.isBuffer(bfr)
var y = Buffer.isBuffer(nobfr)
})
bench('instanceof', function() {
var x = (bfr instanceof Buffer)
var y = (nobfr instanceof Buffer)
})
})
# Just a plain list of people who contributed to this project.
# People who are already listed in AUTHORS are not listed again.
Conrad Pankoff <deoxxa@fknsrs.biz>
Patrick Williams <patrick@bittorrent.com>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Benchmark</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/0.3.0/benchmark.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js"></script>
<script src="./bencode.js"></script>
<script src="./bncode.js"></script>
<script src="./test.js"></script>
<link rel="stylesheet" href="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
</head>
<body>
<div class="col-lg-5" style="margin:auto;float:none;margin-top:3em;">
<div class="panel panel-default">
<div class="panel-heading">decode:</div>
<ul class="list-group" id="results-decode"></ul>
</div>
<div class="panel panel-default">
<div class="panel-heading">encode:</div>
<ul class="list-group" id="results-encode"></ul>
</div>
</div>
<script>
var deepDiffMapper = function() {
return {
VALUE_CREATED: 'created',
VALUE_UPDATED: 'updated',
VALUE_DELETED: 'deleted',
VALUE_UNCHANGED: 'unchanged',
map: function(obj1, obj2) {
if (this.isFunction(obj1) || this.isFunction(obj2)) {
throw 'Invalid argument. Function given, object expected.';
}
if (this.isValue(obj1) || this.isValue(obj2)) {
return {type: this.compareValues(obj1, obj2), data: obj1 || obj2};
}
var diff = {};
for (var key in obj1) {
if (this.isFunction(obj1[key])) {
continue;
}
var value2 = undefined;
if ('undefined' != typeof(obj2[key])) {
value2 = obj2[key];
}
diff[key] = this.map(obj1[key], value2);
}
for (var key in obj2) {
if (this.isFunction(obj2[key]) || ('undefined' != typeof(diff[key]))) {
continue;
}
diff[key] = this.map(undefined, obj2[key]);
}
return diff;
},
compareValues: function(value1, value2) {
if (value1 === value2) {
return this.VALUE_UNCHANGED;
}
if ('undefined' == typeof(value1)) {
return this.VALUE_CREATED;
}
if ('undefined' == typeof(value2)) {
return this.VALUE_DELETED;
}
return this.VALUE_UPDATED;
},
isFunction: function(obj) {
return toString.apply(obj) === '[object Function]';
},
isArray: function(obj) {
return toString.apply(obj) === '[object Array]';
},
isObject: function(obj) {
return toString.apply(obj) === '[object Object]';
},
isValue: function(obj) {
return !this.isObject(obj) && !this.isArray(obj);
}
}
}();
var input = window.data.toString('ascii')
var object_ben = bencode.decode( window.data )
var result_ben = bencode.encode(object_ben).toString('ascii')
console.log(_.isEqual(input, result_ben))
var object_bn = bncode.decode( window.data )
var result_bn = bencode.encode(object_ben).toString('ascii')
console.log(_.isEqual(input, result_bn))
console.log(_.isEqual(result_ben, result_bn))
console.log(object_ben.announce._isBuffer, object_bn.announce._isBuffer)
// add tests
function testDecode(done) {
var suite = new Benchmark.Suite;
suite.add('bencode.decode', function() {
bencode.decode( window.data )
})
.add('bncode.decode', function() {
bncode.decode( window.data )
})
.on( 'cycle', function ( event, bench ) {
var results = document.getElementById('results-decode')
var html = results.innerHTML
html += '<li class="list-group-item" id="result-'+bench.name+'">' + bench.toString()+ '</li>'
results.innerHTML = html
})
.on( 'complete', function ( event, bench ) {
var name = this.filter( 'fastest' ).pluck( 'name' )
document.getElementById('result-' + name).classList.add('list-group-item-success')
done()
})
.run({ async: true })
}
function testEncode(done) {
var suite = new Benchmark.Suite;
suite.add('bencode.encode', function() {
bencode.encode(object_ben)
})
.add('bncode.encode', function() {
bncode.encode(object_ben)
})
.on( 'cycle', function ( event, bench ) {
var results = document.getElementById('results-encode')
var html = results.innerHTML
html += '<li class="list-group-item" id="result-'+bench.name+'">' + bench.toString()+ '</li>'
results.innerHTML = html
})
.on( 'complete', function ( event, bench ) {
var name = this.filter( 'fastest' ).pluck( 'name' )
document.getElementById('result-' + name).classList.add('list-group-item-success')
done()
})
.run({ async: true })
}
testDecode(testEncode.bind(null, function() { console.log('done') }))
</script>
</body>
</html>
!function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.bencode=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
module.exports = {
encode: _dereq_( './lib/encode' ),
decode: _dereq_( './lib/decode' )
}
},{"./lib/decode":2,"./lib/encode":3}],2:[function(_dereq_,module,exports){
(function (Buffer){
/**
* Decodes bencoded data.
*
* @param {Buffer} data
* @param {String} encoding
* @return {Object|Array|Buffer|String|Number}
*/
function decode( data, encoding ) {
decode.position = 0
decode.encoding = encoding || null
decode.data = !( Buffer.isBuffer(data) )
? new Buffer( data )
: data
return decode.next()
}
decode.position = 0
decode.data = null
decode.encoding = null
decode.next = function() {
switch( decode.data[decode.position] ) {
case 0x64: return decode.dictionary(); break
case 0x6C: return decode.list(); break
case 0x69: return decode.integer(); break
default: return decode.bytes(); break
}
}
decode.find = function( chr ) {
var i = decode.position
var c = decode.data.length
var d = decode.data
while( i < c ) {
if( d[i] === chr )
return i
i++
}
throw new Error(
'Invalid data: Missing delimiter "' +
String.fromCharCode( chr ) + '" [0x' +
chr.toString( 16 ) + ']'
)
}
decode.dictionary = function() {
decode.position++
var dict = {}
while( decode.data[decode.position] !== 0x65 ) {
dict[ decode.bytes() ] = decode.next()
}
decode.position++
return dict
}
decode.list = function() {
decode.position++
var lst = []
while( decode.data[decode.position] !== 0x65 ) {
lst.push( decode.next() )
}
decode.position++
return lst
}
decode.integer = function() {
var end = decode.find( 0x65 )
var number = decode.data.toString( 'ascii', decode.position + 1, end )
decode.position += end + 1 - decode.position
return parseInt( number, 10 )
}
decode.bytes = function() {
var sep = decode.find( 0x3A )
var length = parseInt( decode.data.toString( 'ascii', decode.position, sep ), 10 )
var end = ++sep + length
decode.position = end
return decode.encoding
? decode.data.toString( decode.encoding, sep, end )
: decode.data.slice( sep, end )
}
// Exports
module.exports = decode
}).call(this,_dereq_("buffer").Buffer)
},{"buffer":4}],3:[function(_dereq_,module,exports){
(function (Buffer){
/**
* Encodes data in bencode.
*
* @param {Buffer|Array|String|Object|Number} data
* @return {Buffer}
*/
function encode( data ) {
var buffers = []
encode._encode( buffers, data )
return Buffer.concat( buffers )
}
encode._floatConversionDetected = false
encode._encode = function( buffers, data ) {
if( Buffer.isBuffer(data) ) {
buffers.push(new Buffer(data.length + ':'))
buffers.push(data)
return;
}
switch( typeof data ) {
case 'string':
encode.bytes( buffers, data )
break
case 'number':
encode.number( buffers, data )
break
case 'object':
data.constructor === Array
? encode.list( buffers, data )
: encode.dict( buffers, data )
break
}
}
var buff_e = new Buffer('e')
, buff_d = new Buffer('d')
, buff_l = new Buffer('l')
encode.bytes = function( buffers, data ) {
buffers.push( new Buffer(Buffer.byteLength( data ) + ':' + data) )
}
encode.number = function( buffers, data ) {
var maxLo = 0x80000000
var hi = ( data / maxLo ) << 0
var lo = ( data % maxLo ) << 0
var val = hi * maxLo + lo
buffers.push( new Buffer( 'i' + val + 'e' ))
if( val !== data && !encode._floatConversionDetected ) {
encode._floatConversionDetected = true
console.warn(
'WARNING: Possible data corruption detected with value "'+data+'":',
'Bencoding only defines support for integers, value was converted to "'+val+'"'
)
console.trace()
}
}
encode.dict = function( buffers, data ) {
buffers.push( buff_d )
var j = 0
var k
// fix for issue #13 - sorted dicts
var keys = Object.keys( data ).sort()
var kl = keys.length
for( ; j < kl ; j++) {
k=keys[j]
encode.bytes( buffers, k )
encode._encode( buffers, data[k] )
}
buffers.push( buff_e )
}
encode.list = function( buffers, data ) {
var i = 0, j = 1
var c = data.length
buffers.push( buff_l )
for( ; i < c; i++ ) {
encode._encode( buffers, data[i] )
}
buffers.push( buff_e )
}
// Expose
module.exports = encode
}).call(this,_dereq_("buffer").Buffer)
},{"buffer":4}],4:[function(_dereq_,module,exports){
/**
* The buffer module from node.js, for the browser.
*
* Author: Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
* License: MIT
*
* `npm install buffer`
*/
var base64 = _dereq_('base64-js')
var ieee754 = _dereq_('ieee754')
exports.Buffer = Buffer
exports.SlowBuffer = Buffer
exports.INSPECT_MAX_BYTES = 50
Buffer.poolSize = 8192
/**
* If `Buffer._useTypedArrays`:
* === true Use Uint8Array implementation (fastest)
* === false Use Object implementation (compatible down to IE6)
*/
Buffer._useTypedArrays = (function () {
// Detect if browser supports Typed Arrays. Supported browsers are IE 10+,
// Firefox 4+, Chrome 7+, Safari 5.1+, Opera 11.6+, iOS 4.2+.
if (typeof Uint8Array !== 'function' || typeof ArrayBuffer !== 'function')
return false
// Does the browser support adding properties to `Uint8Array` instances? If
// not, then that's the same as no `Uint8Array` support. We need to be able to
// add all the node Buffer API methods.
// Bug in Firefox 4-29, now fixed: https://bugzilla.mozilla.org/show_bug.cgi?id=695438
try {
var arr = new Uint8Array(0)
arr.foo = function () { return 42 }
return 42 === arr.foo() &&
typeof arr.subarray === 'function' // Chrome 9-10 lack `subarray`
} catch (e) {
return false
}
})()
/**
* Class: Buffer
* =============
*
* The Buffer constructor returns instances of `Uint8Array` that are augmented
* with function properties for all the node `Buffer` API functions. We use
* `Uint8Array` so that square bracket notation works as expected -- it returns
* a single octet.
*
* By augmenting the instances, we can avoid modifying the `Uint8Array`
* prototype.
*/
function Buffer (subject, encoding, noZero) {
if (!(this instanceof Buffer))
return new Buffer(subject, encoding, noZero)
var type = typeof subject
// Workaround: node's base64 implementation allows for non-padded strings
// while base64-js does not.
if (encoding === 'base64' && type === 'string') {
subject = stringtrim(subject)
while (subject.length % 4 !== 0) {
subject = subject + '='
}
}
// Find the length
var length
if (type === 'number')
length = coerce(subject)
else if (type === 'string')
length = Buffer.byteLength(subject, encoding)
else if (type === 'object')
length = coerce(subject.length) // Assume object is an array
else
throw new Error('First argument needs to be a number, array or string.')
var buf
if (Buffer._useTypedArrays) {
// Preferred: Return an augmented `Uint8Array` instance for best performance
buf = augment(new Uint8Array(length))
} else {
// Fallback: Return THIS instance of Buffer (created by `new`)
buf = this
buf.length = length
buf._isBuffer = true
}
var i
if (Buffer._useTypedArrays && typeof Uint8Array === 'function' &&
subject instanceof Uint8Array) {
// Speed optimization -- use set if we're copying from a Uint8Array
buf._set(subject)
} else if (isArrayish(subject)) {
// Treat array-ish objects as a byte array
for (i = 0; i < length; i++) {
if (Buffer.isBuffer(subject))
buf[i] = subject.readUInt8(i)
else
buf[i] = subject[i]
}
} else if (type === 'string') {
buf.write(subject, 0, encoding)
} else if (type === 'number' && !Buffer._useTypedArrays && !noZero) {
for (i = 0; i < length; i++) {
buf[i] = 0
}
}
return buf
}
// STATIC METHODS
// ==============
Buffer.isEncoding = function (encoding) {
switch (String(encoding).toLowerCase()) {
case 'hex':
case 'utf8':
case 'utf-8':
case 'ascii':
case 'binary':
case 'base64':
case 'raw':
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
return true
default:
return false
}
}
Buffer.isBuffer = function (b) {
return !!(b !== null && b !== undefined && b._isBuffer)
}
Buffer.byteLength = function (str, encoding) {
var ret
str = str + ''
switch (encoding || 'utf8') {
case 'hex':
ret = str.length / 2
break
case 'utf8':
case 'utf-8':
ret = utf8ToBytes(str).length
break
case 'ascii':
case 'binary':
case 'raw':
ret = str.length
break
case 'base64':
ret = base64ToBytes(str).length
break
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
ret = str.length * 2
break
default:
throw new Error('Unknown encoding')
}
return ret
}
Buffer.concat = function (list, totalLength) {
assert(isArray(list), 'Usage: Buffer.concat(list, [totalLength])\n' +
'list should be an Array.')
if (list.length === 0) {
return new Buffer(0)
} else if (list.length === 1) {
return list[0]
}
var i
if (typeof totalLength !== 'number') {
totalLength = 0
for (i = 0; i < list.length; i++) {
totalLength += list[i].length
}
}
var buf = new Buffer(totalLength)
var pos = 0
for (i = 0; i < list.length; i++) {
var item = list[i]
item.copy(buf, pos)
pos += item.length
}
return buf
}
// BUFFER INSTANCE METHODS
// =======================
function _hexWrite (buf, string, offset, length) {
offset = Number(offset) || 0
var remaining = buf.length - offset
if (!length) {
length = remaining
} else {
length = Number(length)
if (length > remaining) {
length = remaining
}
}
// must be an even number of digits
var strLen = string.length
assert(strLen % 2 === 0, 'Invalid hex string')
if (length > strLen / 2) {
length = strLen / 2
}
for (var i = 0; i < length; i++) {
var byte = parseInt(string.substr(i * 2, 2), 16)
assert(!isNaN(byte), 'Invalid hex string')
buf[offset + i] = byte
}
Buffer._charsWritten = i * 2
return i
}
function _utf8Write (buf, string, offset, length) {
var charsWritten = Buffer._charsWritten =
blitBuffer(utf8ToBytes(string), buf, offset, length)
return charsWritten
}
function _asciiWrite (buf, string, offset, length) {
var charsWritten = Buffer._charsWritten =
blitBuffer(asciiToBytes(string), buf, offset, length)
return charsWritten
}
function _binaryWrite (buf, string, offset, length) {
return _asciiWrite(buf, string, offset, length)
}
function _base64Write (buf, string, offset, length) {
var charsWritten = Buffer._charsWritten =
blitBuffer(base64ToBytes(string), buf, offset, length)
return charsWritten
}
function _utf16leWrite (buf, string, offset, length) {
var charsWritten = Buffer._charsWritten =
blitBuffer(utf16leToBytes(string), buf, offset, length)
return charsWritten
}
Buffer.prototype.write = function (string, offset, length, encoding) {
// Support both (string, offset, length, encoding)
// and the legacy (string, encoding, offset, length)
if (isFinite(offset)) {
if (!isFinite(length)) {
encoding = length
length = undefined
}
} else { // legacy
var swap = encoding
encoding = offset
offset = length
length = swap
}
offset = Number(offset) || 0
var remaining = this.length - offset
if (!length) {
length = remaining
} else {
length = Number(length)
if (length > remaining) {
length = remaining
}
}
encoding = String(encoding || 'utf8').toLowerCase()
var ret
switch (encoding) {
case 'hex':
ret = _hexWrite(this, string, offset, length)
break
case 'utf8':
case 'utf-8':
ret = _utf8Write(this, string, offset, length)
break
case 'ascii':
ret = _asciiWrite(this, string, offset, length)
break
case 'binary':
ret = _binaryWrite(this, string, offset, length)
break
case 'base64':
ret = _base64Write(this, string, offset, length)
break
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
ret = _utf16leWrite(this, string, offset, length)
break
default:
throw new Error('Unknown encoding')
}
return ret
}
Buffer.prototype.toString = function (encoding, start, end) {
var self = this
encoding = String(encoding || 'utf8').toLowerCase()
start = Number(start) || 0
end = (end !== undefined)
? Number(end)
: end = self.length
// Fastpath empty strings
if (end === start)
return ''
var ret
switch (encoding) {
case 'hex':
ret = _hexSlice(self, start, end)
break
case 'utf8':
case 'utf-8':
ret = _utf8Slice(self, start, end)
break
case 'ascii':
ret = _asciiSlice(self, start, end)
break
case 'binary':
ret = _binarySlice(self, start, end)
break
case 'base64':
ret = _base64Slice(self, start, end)
break
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
ret = _utf16leSlice(self, start, end)
break
default:
throw new Error('Unknown encoding')
}
return ret
}
Buffer.prototype.toJSON = function () {
return {
type: 'Buffer',
data: Array.prototype.slice.call(this._arr || this, 0)
}
}
// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
Buffer.prototype.copy = function (target, target_start, start, end) {
var source = this
if (!start) start = 0
if (!end && end !== 0) end = this.length
if (!target_start) target_start = 0
// Copy 0 bytes; we're done
if (end === start) return
if (target.length === 0 || source.length === 0) return
// Fatal error conditions
assert(end >= start, 'sourceEnd < sourceStart')
assert(target_start >= 0 && target_start < target.length,
'targetStart out of bounds')
assert(start >= 0 && start < source.length, 'sourceStart out of bounds')
assert(end >= 0 && end <= source.length, 'sourceEnd out of bounds')
// Are we oob?
if (end > this.length)
end = this.length
if (target.length - target_start < end - start)
end = target.length - target_start + start
// copy!
for (var i = 0; i < end - start; i++)
target[i + target_start] = this[i + start]
}
function _base64Slice (buf, start, end) {
if (start === 0 && end === buf.length) {
return base64.fromByteArray(buf)
} else {
return base64.fromByteArray(buf.slice(start, end))
}
}
function _utf8Slice (buf, start, end) {
var res = ''
var tmp = ''
end = Math.min(buf.length, end)
for (var i = start; i < end; i++) {
if (buf[i] <= 0x7F) {
res += decodeUtf8Char(tmp) + String.fromCharCode(buf[i])
tmp = ''
} else {
tmp += '%' + buf[i].toString(16)
}
}
return res + decodeUtf8Char(tmp)
}
function _asciiSlice (buf, start, end) {
var ret = ''
end = Math.min(buf.length, end)
for (var i = start; i < end; i++)
ret += String.fromCharCode(buf[i])
return ret
}
function _binarySlice (buf, start, end) {
return _asciiSlice(buf, start, end)
}
function _hexSlice (buf, start, end) {
var len = buf.length
if (!start || start < 0) start = 0
if (!end || end < 0 || end > len) end = len
var out = ''
for (var i = start; i < end; i++) {
out += toHex(buf[i])
}
return out
}
function _utf16leSlice (buf, start, end) {
var bytes = buf.slice(start, end)
var res = ''
for (var i = 0; i < bytes.length; i += 2) {
res += String.fromCharCode(bytes[i] + bytes[i+1] * 256)
}
return res
}
Buffer.prototype.slice = function (start, end) {
var len = this.length
start = clamp(start, len, 0)
end = clamp(end, len, len)
if (Buffer._useTypedArrays) {
return augment(this.subarray(start, end))
} else {
var sliceLen = end - start
var newBuf = new Buffer(sliceLen, undefined, true)
for (var i = 0; i < sliceLen; i++) {
newBuf[i] = this[i + start]
}
return newBuf
}
}
// `get` will be removed in Node 0.13+
Buffer.prototype.get = function (offset) {
console.log('.get() is deprecated. Access using array indexes instead.')
return this.readUInt8(offset)
}
// `set` will be removed in Node 0.13+
Buffer.prototype.set = function (v, offset) {
console.log('.set() is deprecated. Access using array indexes instead.')
return this.writeUInt8(v, offset)
}
Buffer.prototype.readUInt8 = function (offset, noAssert) {
if (!noAssert) {
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset < this.length, 'Trying to read beyond buffer length')
}
if (offset >= this.length)
return
return this[offset]
}
function _readUInt16 (buf, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset + 1 < buf.length, 'Trying to read beyond buffer length')
}
var len = buf.length
if (offset >= len)
return
var val
if (littleEndian) {
val = buf[offset]
if (offset + 1 < len)
val |= buf[offset + 1] << 8
} else {
val = buf[offset] << 8
if (offset + 1 < len)
val |= buf[offset + 1]
}
return val
}
Buffer.prototype.readUInt16LE = function (offset, noAssert) {
return _readUInt16(this, offset, true, noAssert)
}
Buffer.prototype.readUInt16BE = function (offset, noAssert) {
return _readUInt16(this, offset, false, noAssert)
}
function _readUInt32 (buf, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset + 3 < buf.length, 'Trying to read beyond buffer length')
}
var len = buf.length
if (offset >= len)
return
var val
if (littleEndian) {
if (offset + 2 < len)
val = buf[offset + 2] << 16
if (offset + 1 < len)
val |= buf[offset + 1] << 8
val |= buf[offset]
if (offset + 3 < len)
val = val + (buf[offset + 3] << 24 >>> 0)
} else {
if (offset + 1 < len)
val = buf[offset + 1] << 16
if (offset + 2 < len)
val |= buf[offset + 2] << 8
if (offset + 3 < len)
val |= buf[offset + 3]
val = val + (buf[offset] << 24 >>> 0)
}
return val
}
Buffer.prototype.readUInt32LE = function (offset, noAssert) {
return _readUInt32(this, offset, true, noAssert)
}
Buffer.prototype.readUInt32BE = function (offset, noAssert) {
return _readUInt32(this, offset, false, noAssert)
}
Buffer.prototype.readInt8 = function (offset, noAssert) {
if (!noAssert) {
assert(offset !== undefined && offset !== null,
'missing offset')
assert(offset < this.length, 'Trying to read beyond buffer length')
}
if (offset >= this.length)
return
var neg = this[offset] & 0x80
if (neg)
return (0xff - this[offset] + 1) * -1
else
return this[offset]
}
function _readInt16 (buf, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset + 1 < buf.length, 'Trying to read beyond buffer length')
}
var len = buf.length
if (offset >= len)
return
var val = _readUInt16(buf, offset, littleEndian, true)
var neg = val & 0x8000
if (neg)
return (0xffff - val + 1) * -1
else
return val
}
Buffer.prototype.readInt16LE = function (offset, noAssert) {
return _readInt16(this, offset, true, noAssert)
}
Buffer.prototype.readInt16BE = function (offset, noAssert) {
return _readInt16(this, offset, false, noAssert)
}
function _readInt32 (buf, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset + 3 < buf.length, 'Trying to read beyond buffer length')
}
var len = buf.length
if (offset >= len)
return
var val = _readUInt32(buf, offset, littleEndian, true)
var neg = val & 0x80000000
if (neg)
return (0xffffffff - val + 1) * -1
else
return val
}
Buffer.prototype.readInt32LE = function (offset, noAssert) {
return _readInt32(this, offset, true, noAssert)
}
Buffer.prototype.readInt32BE = function (offset, noAssert) {
return _readInt32(this, offset, false, noAssert)
}
function _readFloat (buf, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset + 3 < buf.length, 'Trying to read beyond buffer length')
}
return ieee754.read(buf, offset, littleEndian, 23, 4)
}
Buffer.prototype.readFloatLE = function (offset, noAssert) {
return _readFloat(this, offset, true, noAssert)
}
Buffer.prototype.readFloatBE = function (offset, noAssert) {
return _readFloat(this, offset, false, noAssert)
}
function _readDouble (buf, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset + 7 < buf.length, 'Trying to read beyond buffer length')
}
return ieee754.read(buf, offset, littleEndian, 52, 8)
}
Buffer.prototype.readDoubleLE = function (offset, noAssert) {
return _readDouble(this, offset, true, noAssert)
}
Buffer.prototype.readDoubleBE = function (offset, noAssert) {
return _readDouble(this, offset, false, noAssert)
}
Buffer.prototype.writeUInt8 = function (value, offset, noAssert) {
if (!noAssert) {
assert(value !== undefined && value !== null, 'missing value')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset < this.length, 'trying to write beyond buffer length')
verifuint(value, 0xff)
}
if (offset >= this.length) return
this[offset] = value
}
function _writeUInt16 (buf, value, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(value !== undefined && value !== null, 'missing value')
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset + 1 < buf.length, 'trying to write beyond buffer length')
verifuint(value, 0xffff)
}
var len = buf.length
if (offset >= len)
return
for (var i = 0, j = Math.min(len - offset, 2); i < j; i++) {
buf[offset + i] =
(value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>
(littleEndian ? i : 1 - i) * 8
}
}
Buffer.prototype.writeUInt16LE = function (value, offset, noAssert) {
_writeUInt16(this, value, offset, true, noAssert)
}
Buffer.prototype.writeUInt16BE = function (value, offset, noAssert) {
_writeUInt16(this, value, offset, false, noAssert)
}
function _writeUInt32 (buf, value, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(value !== undefined && value !== null, 'missing value')
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset + 3 < buf.length, 'trying to write beyond buffer length')
verifuint(value, 0xffffffff)
}
var len = buf.length
if (offset >= len)
return
for (var i = 0, j = Math.min(len - offset, 4); i < j; i++) {
buf[offset + i] =
(value >>> (littleEndian ? i : 3 - i) * 8) & 0xff
}
}
Buffer.prototype.writeUInt32LE = function (value, offset, noAssert) {
_writeUInt32(this, value, offset, true, noAssert)
}
Buffer.prototype.writeUInt32BE = function (value, offset, noAssert) {
_writeUInt32(this, value, offset, false, noAssert)
}
Buffer.prototype.writeInt8 = function (value, offset, noAssert) {
if (!noAssert) {
assert(value !== undefined && value !== null, 'missing value')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset < this.length, 'Trying to write beyond buffer length')
verifsint(value, 0x7f, -0x80)
}
if (offset >= this.length)
return
if (value >= 0)
this.writeUInt8(value, offset, noAssert)
else
this.writeUInt8(0xff + value + 1, offset, noAssert)
}
function _writeInt16 (buf, value, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(value !== undefined && value !== null, 'missing value')
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset + 1 < buf.length, 'Trying to write beyond buffer length')
verifsint(value, 0x7fff, -0x8000)
}
var len = buf.length
if (offset >= len)
return
if (value >= 0)
_writeUInt16(buf, value, offset, littleEndian, noAssert)
else
_writeUInt16(buf, 0xffff + value + 1, offset, littleEndian, noAssert)
}
Buffer.prototype.writeInt16LE = function (value, offset, noAssert) {
_writeInt16(this, value, offset, true, noAssert)
}
Buffer.prototype.writeInt16BE = function (value, offset, noAssert) {
_writeInt16(this, value, offset, false, noAssert)
}
function _writeInt32 (buf, value, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(value !== undefined && value !== null, 'missing value')
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset + 3 < buf.length, 'Trying to write beyond buffer length')
verifsint(value, 0x7fffffff, -0x80000000)
}
var len = buf.length
if (offset >= len)
return
if (value >= 0)
_writeUInt32(buf, value, offset, littleEndian, noAssert)
else
_writeUInt32(buf, 0xffffffff + value + 1, offset, littleEndian, noAssert)
}
Buffer.prototype.writeInt32LE = function (value, offset, noAssert) {
_writeInt32(this, value, offset, true, noAssert)
}
Buffer.prototype.writeInt32BE = function (value, offset, noAssert) {
_writeInt32(this, value, offset, false, noAssert)
}
function _writeFloat (buf, value, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(value !== undefined && value !== null, 'missing value')
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset + 3 < buf.length, 'Trying to write beyond buffer length')
verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38)
}
var len = buf.length
if (offset >= len)
return
ieee754.write(buf, value, offset, littleEndian, 23, 4)
}
Buffer.prototype.writeFloatLE = function (value, offset, noAssert) {
_writeFloat(this, value, offset, true, noAssert)
}
Buffer.prototype.writeFloatBE = function (value, offset, noAssert) {
_writeFloat(this, value, offset, false, noAssert)
}
function _writeDouble (buf, value, offset, littleEndian, noAssert) {
if (!noAssert) {
assert(value !== undefined && value !== null, 'missing value')
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
assert(offset !== undefined && offset !== null, 'missing offset')
assert(offset + 7 < buf.length,
'Trying to write beyond buffer length')
verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308)
}
var len = buf.length
if (offset >= len)
return
ieee754.write(buf, value, offset, littleEndian, 52, 8)
}
Buffer.prototype.writeDoubleLE = function (value, offset, noAssert) {
_writeDouble(this, value, offset, true, noAssert)
}
Buffer.prototype.writeDoubleBE = function (value, offset, noAssert) {
_writeDouble(this, value, offset, false, noAssert)
}
// fill(value, start=0, end=buffer.length)
Buffer.prototype.fill = function (value, start, end) {
if (!value) value = 0
if (!start) start = 0
if (!end) end = this.length
if (typeof value === 'string') {
value = value.charCodeAt(0)
}
assert(typeof value === 'number' && !isNaN(value), 'value is not a number')
assert(end >= start, 'end < start')
// Fill 0 bytes; we're done
if (end === start) return
if (this.length === 0) return
assert(start >= 0 && start < this.length, 'start out of bounds')
assert(end >= 0 && end <= this.length, 'end out of bounds')
for (var i = start; i < end; i++) {
this[i] = value
}
}
Buffer.prototype.inspect = function () {
var out = []
var len = this.length
for (var i = 0; i < len; i++) {
out[i] = toHex(this[i])
if (i === exports.INSPECT_MAX_BYTES) {
out[i + 1] = '...'
break
}
}
return '<Buffer ' + out.join(' ') + '>'
}
/**
* Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance.
* Added in Node 0.12. Only available in browsers that support ArrayBuffer.
*/
Buffer.prototype.toArrayBuffer = function () {
if (typeof Uint8Array === 'function') {
if (Buffer._useTypedArrays) {
return (new Buffer(this)).buffer
} else {
var buf = new Uint8Array(this.length)
for (var i = 0, len = buf.length; i < len; i += 1)
buf[i] = this[i]
return buf.buffer
}
} else {
throw new Error('Buffer.toArrayBuffer not supported in this browser')
}
}
// HELPER FUNCTIONS
// ================
function stringtrim (str) {
if (str.trim) return str.trim()
return str.replace(/^\s+|\s+$/g, '')
}
var BP = Buffer.prototype
/**
* Augment the Uint8Array *instance* (not the class!) with Buffer methods
*/
function augment (arr) {
arr._isBuffer = true
// save reference to original Uint8Array get/set methods before overwriting
arr._get = arr.get
arr._set = arr.set
// deprecated, will be removed in node 0.13+
arr.get = BP.get
arr.set = BP.set
arr.write = BP.write
arr.toString = BP.toString
arr.toLocaleString = BP.toString
arr.toJSON = BP.toJSON
arr.copy = BP.copy
arr.slice = BP.slice
arr.readUInt8 = BP.readUInt8
arr.readUInt16LE = BP.readUInt16LE
arr.readUInt16BE = BP.readUInt16BE
arr.readUInt32LE = BP.readUInt32LE
arr.readUInt32BE = BP.readUInt32BE
arr.readInt8 = BP.readInt8
arr.readInt16LE = BP.readInt16LE
arr.readInt16BE = BP.readInt16BE
arr.readInt32LE = BP.readInt32LE
arr.readInt32BE = BP.readInt32BE
arr.readFloatLE = BP.readFloatLE
arr.readFloatBE = BP.readFloatBE
arr.readDoubleLE = BP.readDoubleLE
arr.readDoubleBE = BP.readDoubleBE
arr.writeUInt8 = BP.writeUInt8
arr.writeUInt16LE = BP.writeUInt16LE
arr.writeUInt16BE = BP.writeUInt16BE
arr.writeUInt32LE = BP.writeUInt32LE
arr.writeUInt32BE = BP.writeUInt32BE
arr.writeInt8 = BP.writeInt8
arr.writeInt16LE = BP.writeInt16LE
arr.writeInt16BE = BP.writeInt16BE
arr.writeInt32LE = BP.writeInt32LE
arr.writeInt32BE = BP.writeInt32BE
arr.writeFloatLE = BP.writeFloatLE
arr.writeFloatBE = BP.writeFloatBE
arr.writeDoubleLE = BP.writeDoubleLE
arr.writeDoubleBE = BP.writeDoubleBE
arr.fill = BP.fill
arr.inspect = BP.inspect
arr.toArrayBuffer = BP.toArrayBuffer
return arr
}
// slice(start, end)
function clamp (index, len, defaultValue) {
if (typeof index !== 'number') return defaultValue
index = ~~index; // Coerce to integer.
if (index >= len) return len
if (index >= 0) return index
index += len
if (index >= 0) return index
return 0
}
function coerce (length) {
// Coerce length to a number (possibly NaN), round up
// in case it's fractional (e.g. 123.456) then do a
// double negate to coerce a NaN to 0. Easy, right?
length = ~~Math.ceil(+length)
return length < 0 ? 0 : length
}
function isArray (subject) {
return (Array.isArray || function (subject) {
return Object.prototype.toString.call(subject) === '[object Array]'
})(subject)
}
function isArrayish (subject) {
return isArray(subject) || Buffer.isBuffer(subject) ||
subject && typeof subject === 'object' &&
typeof subject.length === 'number'
}
function toHex (n) {
if (n < 16) return '0' + n.toString(16)
return n.toString(16)
}
function utf8ToBytes (str) {
var byteArray = []
for (var i = 0; i < str.length; i++) {
var b = str.charCodeAt(i)
if (b <= 0x7F)
byteArray.push(str.charCodeAt(i))
else {
var start = i
if (b >= 0xD800 && b <= 0xDFFF) i++
var h = encodeURIComponent(str.slice(start, i+1)).substr(1).split('%')
for (var j = 0; j < h.length; j++)
byteArray.push(parseInt(h[j], 16))
}
}
return byteArray
}
function asciiToBytes (str) {
var byteArray = []
for (var i = 0; i < str.length; i++) {
// Node's code seems to be doing this and not & 0x7F..
byteArray.push(str.charCodeAt(i) & 0xFF)
}
return byteArray
}
function utf16leToBytes (str) {
var c, hi, lo
var byteArray = []
for (var i = 0; i < str.length; i++) {
c = str.charCodeAt(i)
hi = c >> 8
lo = c % 256
byteArray.push(lo)
byteArray.push(hi)
}
return byteArray
}
function base64ToBytes (str) {
return base64.toByteArray(str)
}
function blitBuffer (src, dst, offset, length) {
var pos
for (var i = 0; i < length; i++) {
if ((i + offset >= dst.length) || (i >= src.length))
break
dst[i + offset] = src[i]
}
return i
}
function decodeUtf8Char (str) {
try {
return decodeURIComponent(str)
} catch (err) {
return String.fromCharCode(0xFFFD) // UTF 8 invalid char
}
}
/*
* We have to make sure that the value is a valid integer. This means that it
* is non-negative. It has no fractional component and that it does not
* exceed the maximum allowed value.
*/
function verifuint (value, max) {
assert(typeof value === 'number', 'cannot write a non-number as a number')
assert(value >= 0, 'specified a negative value for writing an unsigned value')
assert(value <= max, 'value is larger than maximum value for type')
assert(Math.floor(value) === value, 'value has a fractional component')
}
function verifsint (value, max, min) {
assert(typeof value === 'number', 'cannot write a non-number as a number')
assert(value <= max, 'value larger than maximum allowed value')
assert(value >= min, 'value smaller than minimum allowed value')
assert(Math.floor(value) === value, 'value has a fractional component')
}
function verifIEEE754 (value, max, min) {
assert(typeof value === 'number', 'cannot write a non-number as a number')
assert(value <= max, 'value larger than maximum allowed value')
assert(value >= min, 'value smaller than minimum allowed value')
}
function assert (test, message) {
if (!test) throw new Error(message || 'Failed assertion')
}
},{"base64-js":5,"ieee754":6}],5:[function(_dereq_,module,exports){
var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
;(function (exports) {
'use strict';
var Arr = (typeof Uint8Array !== 'undefined')
? Uint8Array
: Array
var ZERO = '0'.charCodeAt(0)
var PLUS = '+'.charCodeAt(0)
var SLASH = '/'.charCodeAt(0)
var NUMBER = '0'.charCodeAt(0)
var LOWER = 'a'.charCodeAt(0)
var UPPER = 'A'.charCodeAt(0)
function decode (elt) {
var code = elt.charCodeAt(0)
if (code === PLUS)
return 62 // '+'
if (code === SLASH)
return 63 // '/'
if (code < NUMBER)
return -1 //no match
if (code < NUMBER + 10)
return code - NUMBER + 26 + 26
if (code < UPPER + 26)
return code - UPPER
if (code < LOWER + 26)
return code - LOWER + 26
}
function b64ToByteArray (b64) {
var i, j, l, tmp, placeHolders, arr
if (b64.length % 4 > 0) {
throw new Error('Invalid string. Length must be a multiple of 4')
}
// the number of equal signs (place holders)
// if there are two placeholders, than the two characters before it
// represent one byte
// if there is only one, then the three characters before it represent 2 bytes
// this is just a cheap hack to not do indexOf twice
var len = b64.length
placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0
// base64 is 4/3 + up to two characters of the original data
arr = new Arr(b64.length * 3 / 4 - placeHolders)
// if there are placeholders, only get up to the last complete 4 chars
l = placeHolders > 0 ? b64.length - 4 : b64.length
var L = 0
function push (v) {
arr[L++] = v
}
for (i = 0, j = 0; i < l; i += 4, j += 3) {
tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))
push((tmp & 0xFF0000) >> 16)
push((tmp & 0xFF00) >> 8)
push(tmp & 0xFF)
}
if (placeHolders === 2) {
tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)
push(tmp & 0xFF)
} else if (placeHolders === 1) {
tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)
push((tmp >> 8) & 0xFF)
push(tmp & 0xFF)
}
return arr
}
function uint8ToBase64 (uint8) {
var i,
extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
output = "",
temp, length
function encode (num) {
return lookup.charAt(num)
}
function tripletToBase64 (num) {
return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)
}
// go through the array every three bytes, we'll deal with trailing stuff later
for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
output += tripletToBase64(temp)
}
// pad the end with zeros, but make sure to not forget the extra bytes
switch (extraBytes) {
case 1:
temp = uint8[uint8.length - 1]
output += encode(temp >> 2)
output += encode((temp << 4) & 0x3F)
output += '=='
break
case 2:
temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])
output += encode(temp >> 10)
output += encode((temp >> 4) & 0x3F)
output += encode((temp << 2) & 0x3F)
output += '='
break
}
return output
}
module.exports.toByteArray = b64ToByteArray
module.exports.fromByteArray = uint8ToBase64
}())
},{}],6:[function(_dereq_,module,exports){
exports.read = function(buffer, offset, isLE, mLen, nBytes) {
var e, m,
eLen = nBytes * 8 - mLen - 1,
eMax = (1 << eLen) - 1,
eBias = eMax >> 1,
nBits = -7,
i = isLE ? (nBytes - 1) : 0,
d = isLE ? -1 : 1,
s = buffer[offset + i];
i += d;
e = s & ((1 << (-nBits)) - 1);
s >>= (-nBits);
nBits += eLen;
for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8);
m = e & ((1 << (-nBits)) - 1);
e >>= (-nBits);
nBits += mLen;
for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8);
if (e === 0) {
e = 1 - eBias;
} else if (e === eMax) {
return m ? NaN : ((s ? -1 : 1) * Infinity);
} else {
m = m + Math.pow(2, mLen);
e = e - eBias;
}
return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
};
exports.write = function(buffer, value, offset, isLE, mLen, nBytes) {
var e, m, c,
eLen = nBytes * 8 - mLen - 1,
eMax = (1 << eLen) - 1,
eBias = eMax >> 1,
rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0),
i = isLE ? 0 : (nBytes - 1),
d = isLE ? 1 : -1,
s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;
value = Math.abs(value);
if (isNaN(value) || value === Infinity) {
m = isNaN(value) ? 1 : 0;
e = eMax;
} else {
e = Math.floor(Math.log(value) / Math.LN2);
if (value * (c = Math.pow(2, -e)) < 1) {
e--;
c *= 2;
}
if (e + eBias >= 1) {
value += rt / c;
} else {
value += rt * Math.pow(2, 1 - eBias);
}
if (value * c >= 2) {
e++;
c /= 2;
}
if (e + eBias >= eMax) {
m = 0;
e = eMax;
} else if (e + eBias >= 1) {
m = (value * c - 1) * Math.pow(2, mLen);
e = e + eBias;
} else {
m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
e = 0;
}
}
for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8);
e = (e << mLen) | m;
eLen += mLen;
for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8);
buffer[offset + i - d] |= s * 128;
};
},{}]},{},[1])
(1)
});

Sorry, the diff of this file is too big to display

<script src='./tape.js'></script>

Sorry, the diff of this file is too big to display

<script src='tests.js'></script>
window.data = new bencode.Buffer('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', 'base64');

Sorry, the diff of this file is too big to display

module.exports = decode
function* decode(data) {
this.position = 0
this.encoding = encoding || null
this.data = !( data instanceof Buffer )
? new Buffer( data )
: data
while(this.position + 1 < this.data.length) {
switch( this.data[this.position] ) {
case 0x64: yield this.dictionary(); break
case 0x6C: yield this.list(); break
case 0x69: yield this.integer(); break
default: yield this.bytes(); break
}
}
}
.PHONY: all test benchmark
browserify: bencode.js lib/*.js
mkdir -p dist
browserify bencode.js -s bencode -o dist/bencode.js
# TODO: thats not how it should behave!
browser-test: bencode.js lib/*.js test/*.js
mkdir -p dist
browserify test/*.test.js -o dist/tests.js
echo "<script src='tests.js'></script>" > dist/test.html
# open dist/test.html in your browser now
test:
npm test
benchmark:
npm run-script bench
all: browserify test
require('buffer')
//var test = require('tape').test
var bencode = require('./lib.js')
var data = require('./data.js')
/*var input = new Buffer('w6TDtsO8w58=', 'base64')
console.log(data.binKeyName)
var decoded = bencode.decode(data.binKeyData, 'utf8')
console.log(Buffer.byteLength(Object.keys(decoded.files)))
//t.ok(decoded.files.hasOwnProperty(data.binKeyName))
console.log('binKeyName.length', Buffer.byteLength(data.binKeyName.toString('utf8')))
var x = bencode.decode(bencode.encode(data.binKeyName.toString('utf8')))
console.log(x.length)
console.log(x.toString('utf8'))
var bla = {
files: {}
}
bla.files[x] = { complete: 0, downloaded: 10, incomplete: 0 }
console.log(data.binKeyData.toString('utf8'))
console.log(bencode.encode(bla).toString('utf8'))
console.log(bla)*/
var x = {files: { '7�U�ࣚ�K�ϧז����$w': { complete: 0, downloaded: 10, incomplete: 0 } }}
console.log(bencode.encode(x).toString('base64'))
var decoded = bencode.decode(data.binKeyData, 'utf8')
console.log(decoded.files)
var assert = require('assert')
var bencode = require('./lib.js')
var data = require('./data.js')
describe("bencode", function() {
describe("#decode(x)", function() {
it('should be able to decode an integer', function() {
assert.deepEqual(bencode.decode('i123e'), 123);
assert.deepEqual(bencode.decode('i-123e'), -123);
});
it('should be able to decode a float (as int)', function() {
assert.deepEqual(bencode.decode('i12.3e'), 12);
assert.deepEqual(bencode.decode('i-12.3e'), -12);
});
it('should be able to decode a string', function() {
assert.deepEqual(bencode.decode('5:asdfe'), new Buffer('asdfe'));
assert.deepEqual(bencode.decode('4:öö'), new Buffer('öö'));
});
it('should be able to decode "binary keys"', function() {
assert.ok(bencode.decode(data.binKeyData).files.hasOwnProperty(data.binKeyName));
});
it('should be able to decode a dictionary', function() {
assert.deepEqual(
bencode.decode( 'd3:cow3:moo4:spam4:eggse' ),
{
cow: new Buffer('moo'),
spam: new Buffer('eggs')
}
)
assert.deepEqual(
bencode.decode( 'd4:spaml1:a1:bee' ),
{ spam: [
new Buffer('a'),
new Buffer('b')
] }
)
assert.deepEqual(
bencode.decode( 'd9:publisher3:bob17:publisher-webpage15:www.example.com18:publisher.location4:homee'),
{
'publisher': new Buffer('bob'),
'publisher-webpage': new Buffer('www.example.com'),
'publisher.location': new Buffer('home')
}
)
});
it('should be able to decode a list', function() {
assert.deepEqual(
bencode.decode( 'l4:spam4:eggse'),
[ new Buffer('spam'),
new Buffer('eggs') ]
)
});
it('should return the correct type', function() {
assert.ok(bencode.decode('4:öö') instanceof Buffer);
});
it('should be able to decode stuff in dicts (issue #12)', function() {
var someData = {
string: 'Hello World',
integer: 12345,
dict: {
key: 'This is a string within a dictionary'
},
list: [ 1, 2, 3, 4, 'string', 5, {} ]
}
var result = bencode.encode( someData )
var dat = bencode.decode ( result )
assert.equal(dat.integer, 12345)
assert.deepEqual(dat.string, new Buffer("Hello World"))
assert.deepEqual(dat.dict.key, new Buffer("This is a string within a dictionary"))
assert.deepEqual(dat.list, [1, 2, 3, 4, new Buffer('string'), 5, {}])
});
});
});
var assert = require('assert')
var bencode = require('./lib.js')
var data = require('./data.js')
describe("bencode", function() {
describe("#decode(x, 'uft8')", function() {
it('should be able to decode an integer', function() {
assert.deepEqual(bencode.decode('i123e', 'utf8'), 123);
assert.deepEqual(bencode.decode('i-123e', 'utf8'), -123);
});
it('should be able to decode a float (as int)', function() {
assert.deepEqual(bencode.decode('i12.3e', 'utf8'), 12);
assert.deepEqual(bencode.decode('i-12.3e', 'utf8'), -12);
});
it('should be able to decode a string', function() {
assert.deepEqual(bencode.decode('5:asdfe', 'utf8'), 'asdfe');
assert.deepEqual(bencode.decode('4:öö', 'utf8'), 'öö');
});
it('should be able to decode "binary keys"', function() {
var decoded = bencode.decode(data.binKeyData, 'utf8')
assert.ok(decoded.files.hasOwnProperty(data.binKeyName));
});
it('should be able to decode a dictionary', function() {
assert.deepEqual(
bencode.decode( 'd3:cow3:moo4:spam4:eggse', 'utf8' ),
{
cow: 'moo',
spam: 'eggs'
}
)
assert.deepEqual(
bencode.decode( 'd4:spaml1:a1:bee', 'utf8' ),
{ spam: [ 'a', 'b' ] }
)
assert.deepEqual(
bencode.decode( 'd9:publisher3:bob17:publisher-webpage15:www.example.com18:publisher.location4:homee', 'utf8' ),
{
'publisher': 'bob',
'publisher-webpage': 'www.example.com',
'publisher.location': 'home'
}
)
});
it('should be able to decode a list', function() {
assert.deepEqual(
bencode.decode( 'l4:spam4:eggse', 'utf8' ),
[ 'spam', 'eggs' ]
)
});
it('should return the correct type', function() {
assert.ok(typeof(bencode.decode('4:öö', 'utf8')) === 'string');
});
it('should be able to decode stuff in dicts (issue #12)', function() {
var someData = {
string: 'Hello World',
integer: 12345,
dict: {
key: 'This is a string within a dictionary'
},
list: [ 1, 2, 3, 4, 'string', 5, {} ]
}
var result = bencode.encode( someData )
var dat = bencode.decode ( result, 'utf8' )
assert.equal(dat.integer, 12345)
assert.deepEqual(dat.string, "Hello World")
assert.deepEqual(dat.dict.key, "This is a string within a dictionary")
assert.deepEqual(dat.list, [1, 2, 3, 4, 'string', 5, {}])
});
});
});
var assert = require("assert");
var bencode = require('./lib.js');
describe("bencode", function() {
// prevent the warning showing up in the test
bencode.encode._floatConversionDetected = true
describe("#encode()", function() {
it('should always return a Buffer', function() {
assert.ok(Buffer.isBuffer(bencode.encode({})), "its not a buffer for empty dicts");
assert.ok(Buffer.isBuffer(bencode.encode("test")), "its not a buffer for strings");
assert.ok(Buffer.isBuffer(bencode.encode([3, 2])), "its not a buffer for lists");
assert.ok(Buffer.isBuffer(bencode.encode({"a": "b", 3: 6})), "its not a buffer for big dicts");
assert.ok(Buffer.isBuffer(bencode.encode(123)), "its not a buffer for numbers");
});
it('should sort dictionories', function() {
var data = {
string: 'Hello World',
integer: 12345,
};
assert.equal(bencode.encode(data).toString(), "d7:integeri12345e6:string11:Hello Worlde");
})
it('should force keys to be strings', function() {
var data = {
12: 'Hello World',
34: 12345,
};
assert.equal(bencode.encode(data).toString(), "d2:1211:Hello World2:34i12345ee")
})
it('should be able to encode a positive integer', function() {
assert.equal(bencode.encode(123), 'i123e');
})
it('should be able to encode a negative integer', function() {
assert.equal(bencode.encode(-123), 'i-123e');
})
it('should be able to encode a positive float (as int)', function() {
assert.equal(bencode.encode(123.5), 'i123e');
})
it('should be able to encode a negative float (as int)', function() {
assert.equal(bencode.encode(-123.5), 'i-123e');
})
it('should be able to safely encode numbers between -/+ 2 ^ 53 (as ints)', function() {
assert.equal(bencode.encode(0), 'i' + 0 + 'e');
var JAVASCRIPT_INT_BITS = 53;
var MAX_JAVASCRIPT_INT = Math.pow(2, JAVASCRIPT_INT_BITS);
for (var exp = 1; exp < JAVASCRIPT_INT_BITS; ++exp) {
var val = Math.pow(2, exp);
// try the positive and negative
assert.equal(bencode.encode(val), 'i' + val + 'e');
assert.equal(bencode.encode(-val), 'i-' + val + 'e');
// try the value, one above and one below, both positive and negative
var above = val + 1;
var below = val - 1;
assert.equal(bencode.encode(above), 'i' + above + 'e');
assert.equal(bencode.encode(-above), 'i-' + above + 'e');
assert.equal(bencode.encode(below), 'i' + below + 'e');
assert.equal(bencode.encode(-below), 'i-' + below + 'e');
}
assert.equal(bencode.encode(MAX_JAVASCRIPT_INT), 'i' + MAX_JAVASCRIPT_INT + 'e');
assert.equal(bencode.encode(-MAX_JAVASCRIPT_INT), 'i-' + MAX_JAVASCRIPT_INT + 'e');
});
it('should be able to encode a previously problematice 64 bit int', function() {
assert.equal(bencode.encode(2433088826), 'i' + 2433088826 + 'e');
})
it('should be able to encode a negative 64 bit int', function() {
assert.equal(bencode.encode(-0xffffffff), 'i-' + 0xffffffff + 'e');
})
it('should be able to encode a positive 64 bit float (as int)', function() {
assert.equal(bencode.encode(0xffffffff + 0.5), 'i' + 0xffffffff + 'e');
})
it('should be able to encode a negative 64 bit float (as int)', function() {
assert.equal(bencode.encode(-0xffffffff - 0.5), 'i-' + 0xffffffff + 'e');
})
it('should be able to encode a string', function() {
assert.equal(bencode.encode("asdf"), '4:asdf');
assert.equal(bencode.encode(":asdf:"), '6::asdf:');
})
it('should be able to encode a unicode string', function() {
assert.equal(bencode.encode("ö±sdf"), '7:ö±sdf');
assert.equal(bencode.encode(new Buffer("ö±sdf")), '7:ö±sdf');
})
it('should be able to encode a buffer', function() {
assert.equal(bencode.encode(new Buffer("asdf")), '4:asdf');
assert.equal(bencode.encode(new Buffer(":asdf:")), '6::asdf:');
})
it('should be able to encode an array', function() {
assert.equal(bencode.encode([32, 12]), 'li32ei12ee');
assert.equal(bencode.encode([":asdf:"]), 'l6::asdf:e');
})
it('should be able to encode an object', function() {
assert.equal(bencode.encode({"a": "bc"}), 'd1:a2:bce')
assert.equal(bencode.encode({"a": "45", "b": 45}), 'd1:a2:451:bi45ee')
assert.equal(bencode.encode({"a": new Buffer("bc")}), 'd1:a2:bce')
})
})
});
+1
-0

@@ -5,1 +5,2 @@ language: node_js

- 0.10
- 0.11
+2
-2

@@ -13,3 +13,3 @@ /**

decode.data = !( data instanceof Buffer )
decode.data = !( Buffer.isBuffer(data) )
? new Buffer( data )

@@ -97,3 +97,3 @@ : data

return parseInt( number, 10 )
}

@@ -100,0 +100,0 @@

@@ -17,3 +17,3 @@ /**

if( data instanceof Buffer ) {
if( Buffer.isBuffer(data) ) {
buffers.push(new Buffer(data.length + ':'))

@@ -20,0 +20,0 @@ buffers.push(data)

{
"name": "bencode",
"version": "0.5.2",
"version": "0.6.0",
"license": "MIT",
"description": "Bencode de/encoder",
"keywords": [ "torrent", "bittorrent", "bencode", "bdecode", "bencoding" ],
"keywords": [
"torrent",
"bittorrent",
"bencode",
"bdecode",
"bencoding"
],
"contributors": [

@@ -18,7 +23,4 @@ {

}
],
"main": "bencode.js",
"devDependencies": {

@@ -30,10 +32,8 @@ "matcha": "",

"dht.js": "",
"mocha": ""
"tape": "~2.12"
},
"scripts": {
"test": "node node_modules/mocha/bin/mocha",
"test": "node node_modules/tape/bin/tape test/*.test.js",
"bench": "node node_modules/matcha/bin/matcha benchmark/*.js"
},
"repository": {

@@ -43,7 +43,18 @@ "type": "git",

},
"bugs": {
"url": "https://github.com/themasch/node-bencode/issues"
},
"testling": {
"files": "test/*.test.js",
"browsers": [
"ie/6..latest",
"chrome/22..latest",
"firefox/16..latest",
"safari/latest",
"opera/11.0..latest",
"iphone/6..latest",
"ipad/6..latest",
"android-browser/latest"
]
}
}

@@ -1,2 +0,1 @@

# node-bencode [![build status](https://secure.travis-ci.org/themasch/node-bencode.png)](http://travis-ci.org/themasch/node-bencode) [![NPM version](https://badge.fury.io/js/bencode.png)](https://npmjs.org/package/bencode)

@@ -71,2 +70,6 @@

You can also use node-bencode with browserify to be able to use it in a lot of modern browsers.
[![testling results](https://ci.testling.com/themasch/node-bencode.png)](https://ci.testling.com/themasch/node-bencode)
### Encoding

@@ -73,0 +76,0 @@

module.exports = {
binKeyData: new Buffer("ZDU6ZmlsZXNkMjA6N7VVuuCjmp5LoM+n15a5iM/XJHdkODpjb21wbGV0ZWkwZTEwOmRvd25sb2FkZWRpMTBlMTA6aW5jb21wbGV0ZWkwZWVlZQ==", 'base64')
, binKeyName: (new Buffer("N++/vVXvv73go5rvv71L77+9z6fXlu+/ve+/ve+/ve+/vSR3", 'base64')).toString()
//binKeyData: new Buffer("ZDU6ZmlsZXNkMjA6N7VVuuCjmp5LoM+n15a5iM/XJHdkODpjb21wbGV0ZWkwZTEwOmRvd25sb2FkZWRpMTBlMTA6aW5jb21wbGV0ZWkwZWVlZQ==", 'base64')
binKeyData: new Buffer('ZDU6ZmlsZXNkMzY6N++/vVXvv73go5rvv71L77+9z6fXlu+/ve+/ve+/ve+/vSR3ZDg6Y29tcGxldGVpMGUxMDpkb3dubG9hZGVkaTEwZTEwOmluY29tcGxldGVpMGVlZWU=', 'base64')
, binKeyName: new Buffer("N++/vVXvv73go5rvv71L77+9z6fXlu+/ve+/ve+/ve+/vSR3", 'base64')
, binStringData: new Buffer('w7bCsXNkZg==', 'base64')
, binResultData: new Buffer('NzrDtsKxc2Rm', 'base64')
}

@@ -1,75 +0,85 @@

var assert = require('assert')
var test = require('tape').test
var bencode = require('./lib.js')
var data = require('./data.js')
describe("bencode", function() {
describe("#decode(x)", function() {
it('should be able to decode an integer', function() {
assert.deepEqual(bencode.decode('i123e'), 123);
assert.deepEqual(bencode.decode('i-123e'), -123);
});
it('should be able to decode a float (as int)', function() {
assert.deepEqual(bencode.decode('i12.3e'), 12);
assert.deepEqual(bencode.decode('i-12.3e'), -12);
});
it('should be able to decode a string', function() {
assert.deepEqual(bencode.decode('5:asdfe'), new Buffer('asdfe'));
assert.deepEqual(bencode.decode('4:öö'), new Buffer('öö'));
});
it('should be able to decode "binary keys"', function() {
assert.ok(bencode.decode(data.binKeyData).files.hasOwnProperty(data.binKeyName));
});
test("bencode#decode(x)", function(t) {
it('should be able to decode a dictionary', function() {
assert.deepEqual(
bencode.decode( 'd3:cow3:moo4:spam4:eggse' ),
{
cow: new Buffer('moo'),
spam: new Buffer('eggs')
}
)
assert.deepEqual(
bencode.decode( 'd4:spaml1:a1:bee' ),
{ spam: [
new Buffer('a'),
new Buffer('b')
] }
)
assert.deepEqual(
bencode.decode( 'd9:publisher3:bob17:publisher-webpage15:www.example.com18:publisher.location4:homee'),
{
'publisher': new Buffer('bob'),
'publisher-webpage': new Buffer('www.example.com'),
'publisher.location': new Buffer('home')
}
)
});
t.test('should be able to decode an integer', function(t) {
t.plan(2)
t.equal(bencode.decode('i123e'), 123);
t.equal(bencode.decode('i-123e'), -123);
})
it('should be able to decode a list', function() {
assert.deepEqual(
bencode.decode( 'l4:spam4:eggse'),
[ new Buffer('spam'),
new Buffer('eggs') ]
)
});
it('should return the correct type', function() {
assert.ok(bencode.decode('4:öö') instanceof Buffer);
});
it('should be able to decode stuff in dicts (issue #12)', function() {
var someData = {
string: 'Hello World',
integer: 12345,
dict: {
key: 'This is a string within a dictionary'
},
list: [ 1, 2, 3, 4, 'string', 5, {} ]
t.test('should be able to decode a float (as int)', function(t) {
t.plan(2)
t.equal(bencode.decode('i12.3e'), 12);
t.equal(bencode.decode('i-12.3e'), -12);
})
t.test('should be able to decode a string', function(t) {
t.plan(2)
t.deepEqual(bencode.decode('5:asdfe'), new Buffer('asdfe'));
t.deepEqual(bencode.decode(data.binResultData.toString()), data.binStringData);
})
t.test('should be able to decode "binary keys"', function(t) {
t.plan(1)
t.ok(bencode.decode(data.binKeyData).files.hasOwnProperty(data.binKeyName));
})
t.test('should be able to decode a dictionary', function(t) {
t.plan(3)
t.deepEqual(
bencode.decode( 'd3:cow3:moo4:spam4:eggse' ),
{
cow: new Buffer('moo'),
spam: new Buffer('eggs')
}
var result = bencode.encode( someData )
var dat = bencode.decode ( result )
assert.equal(dat.integer, 12345)
assert.deepEqual(dat.string, new Buffer("Hello World"))
assert.deepEqual(dat.dict.key, new Buffer("This is a string within a dictionary"))
assert.deepEqual(dat.list, [1, 2, 3, 4, new Buffer('string'), 5, {}])
});
)
t.deepEqual(
bencode.decode( 'd4:spaml1:a1:bee' ),
{ spam: [
new Buffer('a'),
new Buffer('b')
] }
)
t.deepEqual(
bencode.decode( 'd9:publisher3:bob17:publisher-webpage15:www.example.com18:publisher.location4:homee'),
{
'publisher': new Buffer('bob'),
'publisher-webpage': new Buffer('www.example.com'),
'publisher.location': new Buffer('home')
}
)
});
});
t.test('should be able to decode a list', function(t) {
t.plan(1)
t.deepEqual(
bencode.decode( 'l4:spam4:eggse'),
[ new Buffer('spam'),
new Buffer('eggs') ]
)
})
t.test('should return the correct type', function(t) {
t.plan(1)
t.ok(Buffer.isBuffer(bencode.decode('4:öö')));
})
t.test('should be able to decode stuff in dicts (issue #12)', function(t) {
t.plan(4)
var someData = {
string: 'Hello World',
integer: 12345,
dict: {
key: 'This is a string within a dictionary'
},
list: [ 1, 2, 3, 4, 'string', 5, {} ]
}
var result = bencode.encode( someData )
var dat = bencode.decode ( result )
t.equal(dat.integer, 12345)
t.deepEqual(dat.string, new Buffer("Hello World"))
t.deepEqual(dat.dict.key, new Buffer("This is a string within a dictionary"))
t.deepEqual(dat.list, [1, 2, 3, 4, new Buffer('string'), 5, {}])
})
})

@@ -1,72 +0,79 @@

var assert = require('assert')
var test = require('tape').test
var bencode = require('./lib.js')
var data = require('./data.js')
describe("bencode", function() {
describe("#decode(x, 'uft8')", function() {
it('should be able to decode an integer', function() {
assert.deepEqual(bencode.decode('i123e', 'utf8'), 123);
assert.deepEqual(bencode.decode('i-123e', 'utf8'), -123);
});
it('should be able to decode a float (as int)', function() {
assert.deepEqual(bencode.decode('i12.3e', 'utf8'), 12);
assert.deepEqual(bencode.decode('i-12.3e', 'utf8'), -12);
});
it('should be able to decode a string', function() {
assert.deepEqual(bencode.decode('5:asdfe', 'utf8'), 'asdfe');
assert.deepEqual(bencode.decode('4:öö', 'utf8'), 'öö');
});
it('should be able to decode "binary keys"', function() {
var decoded = bencode.decode(data.binKeyData, 'utf8')
assert.ok(decoded.files.hasOwnProperty(data.binKeyName));
});
test("bencode#decode(x, 'uft8')", function(t) {
t.test('should be able to decode an integer', function(t) {
t.plan(2)
t.equal(bencode.decode('i123e', 'utf8'), 123)
t.equal(bencode.decode('i-123e', 'utf8'), -123)
})
t.test('should be able to decode a float (as int)', function(t) {
t.plan(2)
t.equal(bencode.decode('i12.3e', 'utf8'), 12)
t.equal(bencode.decode('i-12.3e', 'utf8'), -12)
})
t.test('should be able to decode a string', function(t) {
t.plan(2)
t.equal(bencode.decode('5:asdfe', 'utf8'), 'asdfe')
t.deepEqual(bencode.decode(data.binResultData.toString(), 'utf8'), data.binStringData.toString());
})
t.test('should be able to decode "binary keys"', function(t) {
t.plan(1)
var decoded = bencode.decode(data.binKeyData, 'utf8')
t.ok(decoded.files.hasOwnProperty(data.binKeyName.toString('utf8')))
})
it('should be able to decode a dictionary', function() {
assert.deepEqual(
bencode.decode( 'd3:cow3:moo4:spam4:eggse', 'utf8' ),
{
cow: 'moo',
spam: 'eggs'
}
)
assert.deepEqual(
bencode.decode( 'd4:spaml1:a1:bee', 'utf8' ),
{ spam: [ 'a', 'b' ] }
)
assert.deepEqual(
bencode.decode( 'd9:publisher3:bob17:publisher-webpage15:www.example.com18:publisher.location4:homee', 'utf8' ),
{
'publisher': 'bob',
'publisher-webpage': 'www.example.com',
'publisher.location': 'home'
}
)
});
t.test('should be able to decode a dictionary', function(t) {
t.plan(3)
t.deepEqual(
bencode.decode( 'd3:cow3:moo4:spam4:eggse', 'utf8' ),
{
cow: 'moo',
spam: 'eggs'
}
)
t.deepEqual(
bencode.decode( 'd4:spaml1:a1:bee', 'utf8' ),
{ spam: [ 'a', 'b' ] }
)
t.deepEqual(
bencode.decode( 'd9:publisher3:bob17:publisher-webpage15:www.example.com18:publisher.location4:homee', 'utf8' ),
{
'publisher': 'bob',
'publisher-webpage': 'www.example.com',
'publisher.location': 'home'
}
)
})
it('should be able to decode a list', function() {
assert.deepEqual(
bencode.decode( 'l4:spam4:eggse', 'utf8' ),
[ 'spam', 'eggs' ]
)
});
it('should return the correct type', function() {
assert.ok(typeof(bencode.decode('4:öö', 'utf8')) === 'string');
});
it('should be able to decode stuff in dicts (issue #12)', function() {
var someData = {
string: 'Hello World',
integer: 12345,
dict: {
key: 'This is a string within a dictionary'
},
list: [ 1, 2, 3, 4, 'string', 5, {} ]
}
var result = bencode.encode( someData )
var dat = bencode.decode ( result, 'utf8' )
assert.equal(dat.integer, 12345)
assert.deepEqual(dat.string, "Hello World")
assert.deepEqual(dat.dict.key, "This is a string within a dictionary")
assert.deepEqual(dat.list, [1, 2, 3, 4, 'string', 5, {}])
});
});
});
t.test('should be able to decode a list', function(t) {
t.plan(1)
t.deepEqual(
bencode.decode( 'l4:spam4:eggse', 'utf8' ),
[ 'spam', 'eggs' ]
)
})
t.test('should return the correct type', function(t) {
t.plan(1)
t.ok(typeof(bencode.decode('4:öö', 'utf8')) === 'string')
})
t.test('should be able to decode stuff in dicts (issue #12)', function(t) {
t.plan(4)
var someData = {
string: 'Hello World',
integer: 12345,
dict: {
key: 'This is a string within a dictionary'
},
list: [ 1, 2, 3, 4, 'string', 5, {} ]
}
var result = bencode.encode( someData )
var dat = bencode.decode ( result, 'utf8' )
t.equal(dat.integer, 12345)
t.deepEqual(dat.string, "Hello World")
t.deepEqual(dat.dict.key, "This is a string within a dictionary")
t.deepEqual(dat.list, [1, 2, 3, 4, 'string', 5, {}])
})
})

@@ -1,5 +0,6 @@

var assert = require("assert");
var bencode = require('./lib.js');
var test = require('tape').test
var bencode = require('./lib.js')
var data = require('./data.js')
describe("bencode", function() {
test('bencode#encode()', function(t) {

@@ -9,95 +10,111 @@ // prevent the warning showing up in the test

describe("#encode()", function() {
it('should always return a Buffer', function() {
assert.ok(Buffer.isBuffer(bencode.encode({})), "its not a buffer for empty dicts");
assert.ok(Buffer.isBuffer(bencode.encode("test")), "its not a buffer for strings");
assert.ok(Buffer.isBuffer(bencode.encode([3, 2])), "its not a buffer for lists");
assert.ok(Buffer.isBuffer(bencode.encode({"a": "b", 3: 6})), "its not a buffer for big dicts");
assert.ok(Buffer.isBuffer(bencode.encode(123)), "its not a buffer for numbers");
});
it('should sort dictionories', function() {
var data = {
string: 'Hello World',
integer: 12345,
};
assert.equal(bencode.encode(data).toString(), "d7:integeri12345e6:string11:Hello Worlde");
})
it('should force keys to be strings', function() {
var data = {
12: 'Hello World',
34: 12345,
};
assert.equal(bencode.encode(data).toString(), "d2:1211:Hello World2:34i12345ee")
})
it('should be able to encode a positive integer', function() {
assert.equal(bencode.encode(123), 'i123e');
})
it('should be able to encode a negative integer', function() {
assert.equal(bencode.encode(-123), 'i-123e');
})
it('should be able to encode a positive float (as int)', function() {
assert.equal(bencode.encode(123.5), 'i123e');
})
it('should be able to encode a negative float (as int)', function() {
assert.equal(bencode.encode(-123.5), 'i-123e');
})
it('should be able to safely encode numbers between -/+ 2 ^ 53 (as ints)', function() {
assert.equal(bencode.encode(0), 'i' + 0 + 'e');
t.test('should always return a Buffer', function(t) {
t.plan(5)
t.ok(Buffer.isBuffer(bencode.encode({})), "its a buffer for empty dicts")
t.ok(Buffer.isBuffer(bencode.encode("test")), "its a buffer for strings")
t.ok(Buffer.isBuffer(bencode.encode([3, 2])), "its a buffer for lists")
t.ok(Buffer.isBuffer(bencode.encode({"a": "b", 3: 6})), "its a buffer for big dicts")
t.ok(Buffer.isBuffer(bencode.encode(123)), "its a buffer for numbers")
})
var JAVASCRIPT_INT_BITS = 53;
var MAX_JAVASCRIPT_INT = Math.pow(2, JAVASCRIPT_INT_BITS);
t.test('should sort dictionaries', function(t) {
t.plan(1)
var data = { string: 'Hello World', integer: 12345 }
t.equal(bencode.encode(data).toString(), "d7:integeri12345e6:string11:Hello Worlde")
})
for (var exp = 1; exp < JAVASCRIPT_INT_BITS; ++exp) {
var val = Math.pow(2, exp);
// try the positive and negative
assert.equal(bencode.encode(val), 'i' + val + 'e');
assert.equal(bencode.encode(-val), 'i-' + val + 'e');
t.test('should force keys to be strings', function(t) {
t.plan(1)
var data = {
12: 'Hello World',
34: 12345,
}
t.equal(bencode.encode(data).toString(), "d2:1211:Hello World2:34i12345ee")
})
// try the value, one above and one below, both positive and negative
var above = val + 1;
var below = val - 1;
t.test('should be able to encode a positive integer', function(t) {
t.plan(1)
t.equal(bencode.encode(123).toString(), 'i123e')
})
t.test('should be able to encode a negative integer', function(t) {
t.plan(1)
t.equal(bencode.encode(-123).toString(), 'i-123e')
})
t.test('should be able to encode a positive float (as int)', function(t) {
t.plan(1)
t.equal(bencode.encode(123.5).toString(), 'i123e')
})
t.test('should be able to encode a negative float (as int)', function(t) {
t.plan(1)
t.equal(bencode.encode(-123.5).toString(), 'i-123e')
})
assert.equal(bencode.encode(above), 'i' + above + 'e');
assert.equal(bencode.encode(-above), 'i-' + above + 'e');
t.test('should be able to safely encode numbers between -/+ 2 ^ 53 (as ints)', function(t) {
var JAVASCRIPT_INT_BITS = 53
var MAX_JAVASCRIPT_INT = Math.pow(2, JAVASCRIPT_INT_BITS)
assert.equal(bencode.encode(below), 'i' + below + 'e');
assert.equal(bencode.encode(-below), 'i-' + below + 'e');
}
assert.equal(bencode.encode(MAX_JAVASCRIPT_INT), 'i' + MAX_JAVASCRIPT_INT + 'e');
assert.equal(bencode.encode(-MAX_JAVASCRIPT_INT), 'i-' + MAX_JAVASCRIPT_INT + 'e');
});
it('should be able to encode a previously problematice 64 bit int', function() {
assert.equal(bencode.encode(2433088826), 'i' + 2433088826 + 'e');
})
it('should be able to encode a negative 64 bit int', function() {
assert.equal(bencode.encode(-0xffffffff), 'i-' + 0xffffffff + 'e');
})
it('should be able to encode a positive 64 bit float (as int)', function() {
assert.equal(bencode.encode(0xffffffff + 0.5), 'i' + 0xffffffff + 'e');
})
it('should be able to encode a negative 64 bit float (as int)', function() {
assert.equal(bencode.encode(-0xffffffff - 0.5), 'i-' + 0xffffffff + 'e');
})
it('should be able to encode a string', function() {
assert.equal(bencode.encode("asdf"), '4:asdf');
assert.equal(bencode.encode(":asdf:"), '6::asdf:');
})
it('should be able to encode a unicode string', function() {
assert.equal(bencode.encode("ö±sdf"), '7:ö±sdf');
assert.equal(bencode.encode(new Buffer("ö±sdf")), '7:ö±sdf');
})
it('should be able to encode a buffer', function() {
assert.equal(bencode.encode(new Buffer("asdf")), '4:asdf');
assert.equal(bencode.encode(new Buffer(":asdf:")), '6::asdf:');
})
it('should be able to encode an array', function() {
assert.equal(bencode.encode([32, 12]), 'li32ei12ee');
assert.equal(bencode.encode([":asdf:"]), 'l6::asdf:e');
})
it('should be able to encode an object', function() {
assert.equal(bencode.encode({"a": "bc"}), 'd1:a2:bce')
assert.equal(bencode.encode({"a": "45", "b": 45}), 'd1:a2:451:bi45ee')
assert.equal(bencode.encode({"a": new Buffer("bc")}), 'd1:a2:bce')
})
t.plan((JAVASCRIPT_INT_BITS-1) * 6 + 3)
t.equal(bencode.encode(0).toString(), 'i' + 0 + 'e')
for (var exp = 1; exp < JAVASCRIPT_INT_BITS; ++exp) {
var val = Math.pow(2, exp)
// try the positive and negative
t.equal(bencode.encode(val).toString(), 'i' + val + 'e')
t.equal(bencode.encode(-val).toString(), 'i-' + val + 'e')
// try the value, one above and one below, both positive and negative
var above = val + 1
var below = val - 1
t.equal(bencode.encode(above).toString(), 'i' + above + 'e')
t.equal(bencode.encode(-above).toString(), 'i-' + above + 'e')
t.equal(bencode.encode(below).toString(), 'i' + below + 'e')
t.equal(bencode.encode(-below).toString(), 'i-' + below + 'e')
}
t.equal(bencode.encode(MAX_JAVASCRIPT_INT).toString(), 'i' + MAX_JAVASCRIPT_INT + 'e')
t.equal(bencode.encode(-MAX_JAVASCRIPT_INT).toString(), 'i-' + MAX_JAVASCRIPT_INT + 'e')
})
});
t.test('should be able to encode a previously problematice 64 bit int', function(t) {
t.plan(1)
t.equal(bencode.encode(2433088826).toString(), 'i' + 2433088826 + 'e')
})
t.test('should be able to encode a negative 64 bit int', function(t) {
t.plan(1)
t.equal(bencode.encode(-0xffffffff).toString(), 'i-' + 0xffffffff + 'e')
})
t.test('should be able to encode a positive 64 bit float (as int)', function(t) {
t.plan(1)
t.equal(bencode.encode(0xffffffff + 0.5).toString(), 'i' + 0xffffffff + 'e')
})
t.test('should be able to encode a negative 64 bit float (as int)', function(t) {
t.plan(1)
t.equal(bencode.encode(-0xffffffff - 0.5).toString(), 'i-' + 0xffffffff + 'e')
})
t.test('should be able to encode a string', function(t) {
t.plan(2)
t.equal(bencode.encode("asdf").toString(), '4:asdf')
t.equal(bencode.encode(":asdf:").toString(), '6::asdf:')
})
t.test('should be able to encode a unicode string', function(t) {
t.plan(2)
t.deepEqual(bencode.encode(data.binStringData.toString()), data.binResultData)
t.deepEqual(bencode.encode(data.binStringData.toString()), data.binResultData)
})
t.test('should be able to encode a buffer', function(t) {
t.plan(2)
t.equal(bencode.encode(new Buffer("asdf")).toString(), '4:asdf')
t.equal(bencode.encode(new Buffer(":asdf:")).toString(), '6::asdf:')
})
t.test('should be able to encode an array', function(t) {
t.plan(2)
t.equal(bencode.encode([32, 12]).toString(), 'li32ei12ee')
t.equal(bencode.encode([":asdf:"]).toString(), 'l6::asdf:e')
})
t.test('should be able to encode an object', function(t) {
t.plan(3)
t.equal(bencode.encode({"a": "bc"}).toString(), 'd1:a2:bce')
t.equal(bencode.encode({"a": "45", "b": 45}).toString(), 'd1:a2:451:bi45ee')
t.equal(bencode.encode({"a": new Buffer("bc")}).toString(), 'd1:a2:bce')
})
})
"use strict";
var util = require('util')
, events = require('events')
, microtime = require('microtime')
var Benchmark = {
Test: require('./test.js')
, Suite: require('./suite.js')
}
module.exports = Benchmark;
"use strict";
var util = require('util')
, events = require('events')
, Test = require('./test.js')
var Suite = function(options)
{
if(!(this instanceof Suite)) {
return new Suite(options)
}
events.EventEmitter.call(this)
this.options = options || {}
this.tests = []
}
util.inherits(Suite, events.EventEmitter)
Suite.prototype.add = function(name, test, options)
{
this.tests.push( new Test(name, test, options, this) )
return this
}
Suite.prototype.run = function(options)
{
var tl = this.tests.length
var results = {}
for(var a=0;a<5;a++) {
for(var i=0;i<tl;i++) {
var test = this.tests[i]
var samples = test.run(options)
if(!results[test.name]) {
results[test.name] = samples
}
else {
for(var j=0;j<samples.length;j++) {
results[test.name].push(samples[j])
}
}
}
}
var stats = {}
for(var i=0;i<tl;i++) {
var test = this.tests[i]
var s = results[test.name]
stats[test.name] = this.doMathStuff(s)
}
console.log(stats)
}
Suite.prototype.doMathStuff = function(samples) {
var l = samples.length
var time = 0, runs = 0
var maxOPS = 0
, minOPS = Infinity
for(var i=0; i < l ; i++ ) {
time += samples[i][0]
runs += samples[i][1]
maxOPS = Math.max(samples[i][2], maxOPS)
minOPS = Math.min(samples[i][2], minOPS)
}
return {
avg: runs/time * 1e9,
best: maxOPS,
worst: minOPS
}
}
module.exports = Suite
exports.merge_objs = function() {
var result = {}
for( var i = 0 ; i < arguments.length ; i++ ) {
var obj = arguments[i]
if(typeof obj !== 'object') {
continue
}
var keys = Object.getOwnPropertyNames(obj)
var keyl = keys.length
for( var j = 0 ; j < keyl ; j++ ) {
var key = keys[j]
result[key] = obj[key]
}
}
return result
}
exports.time = function() {
var t = process.hrtime()
return t[0]*1e9 + t[1]
}