bl.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. var DuplexStream = require('readable-stream/duplex')
  2. , util = require('util')
  3. function BufferList (callback) {
  4. if (!(this instanceof BufferList))
  5. return new BufferList(callback)
  6. this._bufs = []
  7. this.length = 0
  8. if (typeof callback == 'function') {
  9. this._callback = callback
  10. var piper = function (err) {
  11. if (this._callback) {
  12. this._callback(err)
  13. this._callback = null
  14. }
  15. }.bind(this)
  16. this.on('pipe', function (src) {
  17. src.on('error', piper)
  18. })
  19. this.on('unpipe', function (src) {
  20. src.removeListener('error', piper)
  21. })
  22. }
  23. else if (Buffer.isBuffer(callback))
  24. this.append(callback)
  25. else if (Array.isArray(callback)) {
  26. callback.forEach(function (b) {
  27. Buffer.isBuffer(b) && this.append(b)
  28. }.bind(this))
  29. }
  30. DuplexStream.call(this)
  31. }
  32. util.inherits(BufferList, DuplexStream)
  33. BufferList.prototype._offset = function (offset) {
  34. var tot = 0, i = 0, _t
  35. for (; i < this._bufs.length; i++) {
  36. _t = tot + this._bufs[i].length
  37. if (offset < _t)
  38. return [ i, offset - tot ]
  39. tot = _t
  40. }
  41. }
  42. BufferList.prototype.append = function (buf) {
  43. var isBuffer = Buffer.isBuffer(buf) ||
  44. buf instanceof BufferList
  45. // coerce number arguments to strings, since Buffer(number) does
  46. // uninitialized memory allocation
  47. if (typeof buf == 'number')
  48. buf = buf.toString()
  49. this._bufs.push(isBuffer ? buf : new Buffer(buf))
  50. this.length += buf.length
  51. return this
  52. }
  53. BufferList.prototype._write = function (buf, encoding, callback) {
  54. this.append(buf)
  55. if (callback)
  56. callback()
  57. }
  58. BufferList.prototype._read = function (size) {
  59. if (!this.length)
  60. return this.push(null)
  61. size = Math.min(size, this.length)
  62. this.push(this.slice(0, size))
  63. this.consume(size)
  64. }
  65. BufferList.prototype.end = function (chunk) {
  66. DuplexStream.prototype.end.call(this, chunk)
  67. if (this._callback) {
  68. this._callback(null, this.slice())
  69. this._callback = null
  70. }
  71. }
  72. BufferList.prototype.get = function (index) {
  73. return this.slice(index, index + 1)[0]
  74. }
  75. BufferList.prototype.slice = function (start, end) {
  76. return this.copy(null, 0, start, end)
  77. }
  78. BufferList.prototype.copy = function (dst, dstStart, srcStart, srcEnd) {
  79. if (typeof srcStart != 'number' || srcStart < 0)
  80. srcStart = 0
  81. if (typeof srcEnd != 'number' || srcEnd > this.length)
  82. srcEnd = this.length
  83. if (srcStart >= this.length)
  84. return dst || new Buffer(0)
  85. if (srcEnd <= 0)
  86. return dst || new Buffer(0)
  87. var copy = !!dst
  88. , off = this._offset(srcStart)
  89. , len = srcEnd - srcStart
  90. , bytes = len
  91. , bufoff = (copy && dstStart) || 0
  92. , start = off[1]
  93. , l
  94. , i
  95. // copy/slice everything
  96. if (srcStart === 0 && srcEnd == this.length) {
  97. if (!copy) // slice, just return a full concat
  98. return Buffer.concat(this._bufs)
  99. // copy, need to copy individual buffers
  100. for (i = 0; i < this._bufs.length; i++) {
  101. this._bufs[i].copy(dst, bufoff)
  102. bufoff += this._bufs[i].length
  103. }
  104. return dst
  105. }
  106. // easy, cheap case where it's a subset of one of the buffers
  107. if (bytes <= this._bufs[off[0]].length - start) {
  108. return copy
  109. ? this._bufs[off[0]].copy(dst, dstStart, start, start + bytes)
  110. : this._bufs[off[0]].slice(start, start + bytes)
  111. }
  112. if (!copy) // a slice, we need something to copy in to
  113. dst = new Buffer(len)
  114. for (i = off[0]; i < this._bufs.length; i++) {
  115. l = this._bufs[i].length - start
  116. if (bytes > l) {
  117. this._bufs[i].copy(dst, bufoff, start)
  118. } else {
  119. this._bufs[i].copy(dst, bufoff, start, start + bytes)
  120. break
  121. }
  122. bufoff += l
  123. bytes -= l
  124. if (start)
  125. start = 0
  126. }
  127. return dst
  128. }
  129. BufferList.prototype.toString = function (encoding, start, end) {
  130. return this.slice(start, end).toString(encoding)
  131. }
  132. BufferList.prototype.consume = function (bytes) {
  133. while (this._bufs.length) {
  134. if (bytes > this._bufs[0].length) {
  135. bytes -= this._bufs[0].length
  136. this.length -= this._bufs[0].length
  137. this._bufs.shift()
  138. } else {
  139. this._bufs[0] = this._bufs[0].slice(bytes)
  140. this.length -= bytes
  141. break
  142. }
  143. }
  144. return this
  145. }
  146. BufferList.prototype.duplicate = function () {
  147. var i = 0
  148. , copy = new BufferList()
  149. for (; i < this._bufs.length; i++)
  150. copy.append(this._bufs[i])
  151. return copy
  152. }
  153. BufferList.prototype.destroy = function () {
  154. this._bufs.length = 0;
  155. this.length = 0;
  156. this.push(null);
  157. }
  158. ;(function () {
  159. var methods = {
  160. 'readDoubleBE' : 8
  161. , 'readDoubleLE' : 8
  162. , 'readFloatBE' : 4
  163. , 'readFloatLE' : 4
  164. , 'readInt32BE' : 4
  165. , 'readInt32LE' : 4
  166. , 'readUInt32BE' : 4
  167. , 'readUInt32LE' : 4
  168. , 'readInt16BE' : 2
  169. , 'readInt16LE' : 2
  170. , 'readUInt16BE' : 2
  171. , 'readUInt16LE' : 2
  172. , 'readInt8' : 1
  173. , 'readUInt8' : 1
  174. }
  175. for (var m in methods) {
  176. (function (m) {
  177. BufferList.prototype[m] = function (offset) {
  178. return this.slice(offset, offset + methods[m])[m](0)
  179. }
  180. }(m))
  181. }
  182. }())
  183. module.exports = BufferList