streams.js (3387B)
1 "use strict"; 2 3 var Buffer = require("buffer").Buffer, 4 Transform = require("stream").Transform; 5 6 7 // == Exports ================================================================== 8 module.exports = function(iconv) { 9 10 // Additional Public API. 11 iconv.encodeStream = function encodeStream(encoding, options) { 12 return new IconvLiteEncoderStream(iconv.getEncoder(encoding, options), options); 13 } 14 15 iconv.decodeStream = function decodeStream(encoding, options) { 16 return new IconvLiteDecoderStream(iconv.getDecoder(encoding, options), options); 17 } 18 19 iconv.supportsStreams = true; 20 21 22 // Not published yet. 23 iconv.IconvLiteEncoderStream = IconvLiteEncoderStream; 24 iconv.IconvLiteDecoderStream = IconvLiteDecoderStream; 25 iconv._collect = IconvLiteDecoderStream.prototype.collect; 26 }; 27 28 29 // == Encoder stream ======================================================= 30 function IconvLiteEncoderStream(conv, options) { 31 this.conv = conv; 32 options = options || {}; 33 options.decodeStrings = false; // We accept only strings, so we don't need to decode them. 34 Transform.call(this, options); 35 } 36 37 IconvLiteEncoderStream.prototype = Object.create(Transform.prototype, { 38 constructor: { value: IconvLiteEncoderStream } 39 }); 40 41 IconvLiteEncoderStream.prototype._transform = function(chunk, encoding, done) { 42 if (typeof chunk != 'string') 43 return done(new Error("Iconv encoding stream needs strings as its input.")); 44 try { 45 var res = this.conv.write(chunk); 46 if (res && res.length) this.push(res); 47 done(); 48 } 49 catch (e) { 50 done(e); 51 } 52 } 53 54 IconvLiteEncoderStream.prototype._flush = function(done) { 55 try { 56 var res = this.conv.end(); 57 if (res && res.length) this.push(res); 58 done(); 59 } 60 catch (e) { 61 done(e); 62 } 63 } 64 65 IconvLiteEncoderStream.prototype.collect = function(cb) { 66 var chunks = []; 67 this.on('error', cb); 68 this.on('data', function(chunk) { chunks.push(chunk); }); 69 this.on('end', function() { 70 cb(null, Buffer.concat(chunks)); 71 }); 72 return this; 73 } 74 75 76 // == Decoder stream ======================================================= 77 function IconvLiteDecoderStream(conv, options) { 78 this.conv = conv; 79 options = options || {}; 80 options.encoding = this.encoding = 'utf8'; // We output strings. 81 Transform.call(this, options); 82 } 83 84 IconvLiteDecoderStream.prototype = Object.create(Transform.prototype, { 85 constructor: { value: IconvLiteDecoderStream } 86 }); 87 88 IconvLiteDecoderStream.prototype._transform = function(chunk, encoding, done) { 89 if (!Buffer.isBuffer(chunk)) 90 return done(new Error("Iconv decoding stream needs buffers as its input.")); 91 try { 92 var res = this.conv.write(chunk); 93 if (res && res.length) this.push(res, this.encoding); 94 done(); 95 } 96 catch (e) { 97 done(e); 98 } 99 } 100 101 IconvLiteDecoderStream.prototype._flush = function(done) { 102 try { 103 var res = this.conv.end(); 104 if (res && res.length) this.push(res, this.encoding); 105 done(); 106 } 107 catch (e) { 108 done(e); 109 } 110 } 111 112 IconvLiteDecoderStream.prototype.collect = function(cb) { 113 var res = ''; 114 this.on('error', cb); 115 this.on('data', function(chunk) { res += chunk; }); 116 this.on('end', function() { 117 cb(null, res); 118 }); 119 return this; 120 } 121