UNPKG

2.79 kBJavaScriptView Raw
1var util = require('util')
2var Stream = require('stream')
3var StringDecoder = require('string_decoder').StringDecoder
4
5module.exports = StringStream
6module.exports.AlignedStringDecoder = AlignedStringDecoder
7
8function StringStream(from, to) {
9 if (!(this instanceof StringStream)) return new StringStream(from, to)
10
11 Stream.call(this)
12
13 if (from == null) from = 'utf8'
14
15 this.readable = this.writable = true
16 this.paused = false
17 this.toEncoding = (to == null ? from : to)
18 this.fromEncoding = (to == null ? '' : from)
19 this.decoder = new AlignedStringDecoder(this.toEncoding)
20}
21util.inherits(StringStream, Stream)
22
23StringStream.prototype.write = function(data) {
24 if (!this.writable) {
25 var err = new Error('stream not writable')
26 err.code = 'EPIPE'
27 this.emit('error', err)
28 return false
29 }
30 if (this.fromEncoding) {
31 if (Buffer.isBuffer(data)) data = data.toString()
32 data = new Buffer(data, this.fromEncoding)
33 }
34 var string = this.decoder.write(data)
35 if (string.length) this.emit('data', string)
36 return !this.paused
37}
38
39StringStream.prototype.flush = function() {
40 if (this.decoder.flush) {
41 var string = this.decoder.flush()
42 if (string.length) this.emit('data', string)
43 }
44}
45
46StringStream.prototype.end = function() {
47 if (!this.writable && !this.readable) return
48 this.flush()
49 this.emit('end')
50 this.writable = this.readable = false
51 this.destroy()
52}
53
54StringStream.prototype.destroy = function() {
55 this.decoder = null
56 this.writable = this.readable = false
57 this.emit('close')
58}
59
60StringStream.prototype.pause = function() {
61 this.paused = true
62}
63
64StringStream.prototype.resume = function () {
65 if (this.paused) this.emit('drain')
66 this.paused = false
67}
68
69function AlignedStringDecoder(encoding) {
70 StringDecoder.call(this, encoding)
71
72 switch (this.encoding) {
73 case 'base64':
74 this.write = alignedWrite
75 this.alignedBuffer = new Buffer(3)
76 this.alignedBytes = 0
77 break
78 }
79}
80util.inherits(AlignedStringDecoder, StringDecoder)
81
82AlignedStringDecoder.prototype.flush = function() {
83 if (!this.alignedBuffer || !this.alignedBytes) return ''
84 var leftover = this.alignedBuffer.toString(this.encoding, 0, this.alignedBytes)
85 this.alignedBytes = 0
86 return leftover
87}
88
89function alignedWrite(buffer) {
90 var rem = (this.alignedBytes + buffer.length) % this.alignedBuffer.length
91 if (!rem && !this.alignedBytes) return buffer.toString(this.encoding)
92
93 var returnBuffer = new Buffer(this.alignedBytes + buffer.length - rem)
94
95 this.alignedBuffer.copy(returnBuffer, 0, 0, this.alignedBytes)
96 buffer.copy(returnBuffer, this.alignedBytes, 0, buffer.length - rem)
97
98 buffer.copy(this.alignedBuffer, 0, buffer.length - rem, buffer.length)
99 this.alignedBytes = rem
100
101 return returnBuffer.toString(this.encoding)
102}