@@ -1,52 +1,104 @@
-var stream = require('stream')
-var bops = require('bops')
-var util = require('util')
-
-function ConcatStream(cb) {
- stream.Stream.call(this)
- this.writable = true
- if (cb) this.cb = cb
- this.body = []
- this.on('error', function(err) {
- // no-op
- })
-}
+var Writable = require('stream').Writable
+var inherits = require('inherits')
+var TA = require('typedarray')
+var U8 = typeof Uint8Array !== 'undefined' ? Uint8Array : TA.Uint8Array
+
+function ConcatStream(opts, cb) {
+ if (!(this instanceof ConcatStream)) return new ConcatStream(opts, cb)
+
+ if (typeof opts === 'function') {
+ cb = opts
+ opts = {}
+ }
+ if (!opts) opts = {}
+
+ var encoding = String(opts.encoding || 'buffer').toLowerCase()
+ if (encoding === 'u8' || encoding === 'uint8') {
+ encoding = 'uint8array'
+ }
+ Writable.call(this, { objectMode: true })
-util.inherits(ConcatStream, stream.Stream)
+ this.encoding = encoding
-ConcatStream.prototype.write = function(chunk) {
- this.emit('data', chunk)
- this.body.push(chunk)
+ if (cb) this.on('finish', function () { cb(this.getBody()) })
+ this.body = []
}
-ConcatStream.prototype.destroy = function() {}
-
-ConcatStream.prototype.arrayConcat = function(arrs) {
- if (arrs.length === 0) return []
- if (arrs.length === 1) return arrs[0]
- return arrs.reduce(function (a, b) { return a.concat(b) })
-}
+module.exports = ConcatStream
+inherits(ConcatStream, Writable)
-ConcatStream.prototype.isArray = function(arr) {
- return Object.prototype.toString.call(arr) == '[object Array]'
+ConcatStream.prototype._write = function(chunk, enc, next) {
+ this.body.push(chunk)
+ next()
}
ConcatStream.prototype.getBody = function () {
- if (this.body.length === 0) return bops.from(0)
- if (typeof(this.body[0]) === "string") return this.body.join('')
- if (this.isArray(this.body[0])) return this.arrayConcat(this.body)
- if (bops.is(this.body[0])) return bops.join(this.body)
+ if (this.encoding === 'array') return arrayConcat(this.body)
+ if (this.encoding === 'string') return stringConcat(this.body)
+ if (this.encoding === 'buffer') return bufferConcat(this.body)
+ if (this.encoding === 'uint8array') return u8Concat(this.body)
return this.body
}
-ConcatStream.prototype.end = function(chunk) {
- if (chunk) this.write(chunk)
- this.emit('end')
- if (this.cb) this.cb(this.getBody())
+var isArray = Array.isArray || function (arr) {
+ return Object.prototype.toString.call(arr) == '[object Array]'
}
-module.exports = function(cb) {
- return new ConcatStream(cb)
+function isArrayish (arr) {
+ return /Array\]$/.test(Object.prototype.toString.call(arr))
}
-module.exports.ConcatStream = ConcatStream
+function stringConcat (parts) {
+ var strings = []
+ for (var i = 0; i < parts.length; i++) {
+ var p = parts[i]
+ if (typeof p === 'string') {
+ strings.push(p)
+ } else if (Buffer.isBuffer(p)) {
+ strings.push(p.toString('utf8'))
+ } else {
+ strings.push(Buffer(p).toString('utf8'))
+ }
+ }
+ return strings.join('')
+}
+
+function bufferConcat (parts) {
+ var bufs = []
+ for (var i = 0; i < parts.length; i++) {
+ var p = parts[i]
+ if (Buffer.isBuffer(p)) {
+ bufs.push(p)
+ } else if (typeof p === 'string' || isArrayish(p)
+ || (p && typeof p.subarray === 'function')) {
+ bufs.push(Buffer(p))
+ } else bufs.push(Buffer(String(p)))
+ }
+ return Buffer.concat(bufs)
+}
+
+function arrayConcat (parts) {
+ var res = []
+ for (var i = 0; i < parts.length; i++) {
+ res.push.apply(res, parts[i])
+ }
+ return res
+}
+
+function u8Concat (parts) {
+ var len = 0
+ for (var i = 0; i < parts.length; i++) {
+ if (typeof parts[i] === 'string') {
+ parts[i] = Buffer(parts[i])
+ }
+ len += parts[i].length
+ }
+ var u8 = new U8(len)
+ for (var i = 0, offset = 0; i < parts.length; i++) {
+ var part = parts[i]
+ for (var j = 0; j < part.length; j++) {
+ u8[offset++] = part[j]
+ }
+ }
+ return u8
+}