| [81bc7da] | 1 | 'use strict';
|
|---|
| 2 |
|
|---|
| 3 | const stream = require('stream');
|
|---|
| 4 | const Transform = stream.Transform;
|
|---|
| 5 |
|
|---|
| 6 | /**
|
|---|
| 7 | * Escapes dots in the beginning of lines. Ends the stream with <CR><LF>.<CR><LF>
|
|---|
| 8 | * Also makes sure that only <CR><LF> sequences are used for linebreaks
|
|---|
| 9 | *
|
|---|
| 10 | * @param {Object} options Stream options
|
|---|
| 11 | */
|
|---|
| 12 | class DataStream extends Transform {
|
|---|
| 13 | constructor(options) {
|
|---|
| 14 | super(options);
|
|---|
| 15 | // init Transform
|
|---|
| 16 | this.options = options || {};
|
|---|
| 17 | this._curLine = '';
|
|---|
| 18 |
|
|---|
| 19 | this.inByteCount = 0;
|
|---|
| 20 | this.outByteCount = 0;
|
|---|
| 21 | this.lastByte = false;
|
|---|
| 22 | }
|
|---|
| 23 |
|
|---|
| 24 | /**
|
|---|
| 25 | * Escapes dots
|
|---|
| 26 | */
|
|---|
| 27 | _transform(chunk, encoding, done) {
|
|---|
| 28 | let chunks = [];
|
|---|
| 29 | let chunklen = 0;
|
|---|
| 30 | let i,
|
|---|
| 31 | len,
|
|---|
| 32 | lastPos = 0;
|
|---|
| 33 | let buf;
|
|---|
| 34 |
|
|---|
| 35 | if (!chunk || !chunk.length) {
|
|---|
| 36 | return done();
|
|---|
| 37 | }
|
|---|
| 38 |
|
|---|
| 39 | if (typeof chunk === 'string') {
|
|---|
| 40 | chunk = Buffer.from(chunk);
|
|---|
| 41 | }
|
|---|
| 42 |
|
|---|
| 43 | this.inByteCount += chunk.length;
|
|---|
| 44 |
|
|---|
| 45 | for (i = 0, len = chunk.length; i < len; i++) {
|
|---|
| 46 | if (chunk[i] === 0x2e) {
|
|---|
| 47 | // .
|
|---|
| 48 | if ((i && chunk[i - 1] === 0x0a) || (!i && (!this.lastByte || this.lastByte === 0x0a))) {
|
|---|
| 49 | buf = chunk.slice(lastPos, i + 1);
|
|---|
| 50 | chunks.push(buf);
|
|---|
| 51 | chunks.push(Buffer.from('.'));
|
|---|
| 52 | chunklen += buf.length + 1;
|
|---|
| 53 | lastPos = i + 1;
|
|---|
| 54 | }
|
|---|
| 55 | } else if (chunk[i] === 0x0a) {
|
|---|
| 56 | // .
|
|---|
| 57 | if ((i && chunk[i - 1] !== 0x0d) || (!i && this.lastByte !== 0x0d)) {
|
|---|
| 58 | if (i > lastPos) {
|
|---|
| 59 | buf = chunk.slice(lastPos, i);
|
|---|
| 60 | chunks.push(buf);
|
|---|
| 61 | chunklen += buf.length + 2;
|
|---|
| 62 | } else {
|
|---|
| 63 | chunklen += 2;
|
|---|
| 64 | }
|
|---|
| 65 | chunks.push(Buffer.from('\r\n'));
|
|---|
| 66 | lastPos = i + 1;
|
|---|
| 67 | }
|
|---|
| 68 | }
|
|---|
| 69 | }
|
|---|
| 70 |
|
|---|
| 71 | if (chunklen) {
|
|---|
| 72 | // add last piece
|
|---|
| 73 | if (lastPos < chunk.length) {
|
|---|
| 74 | buf = chunk.slice(lastPos);
|
|---|
| 75 | chunks.push(buf);
|
|---|
| 76 | chunklen += buf.length;
|
|---|
| 77 | }
|
|---|
| 78 |
|
|---|
| 79 | this.outByteCount += chunklen;
|
|---|
| 80 | this.push(Buffer.concat(chunks, chunklen));
|
|---|
| 81 | } else {
|
|---|
| 82 | this.outByteCount += chunk.length;
|
|---|
| 83 | this.push(chunk);
|
|---|
| 84 | }
|
|---|
| 85 |
|
|---|
| 86 | this.lastByte = chunk[chunk.length - 1];
|
|---|
| 87 | done();
|
|---|
| 88 | }
|
|---|
| 89 |
|
|---|
| 90 | /**
|
|---|
| 91 | * Finalizes the stream with a dot on a single line
|
|---|
| 92 | */
|
|---|
| 93 | _flush(done) {
|
|---|
| 94 | let buf;
|
|---|
| 95 | if (this.lastByte === 0x0a) {
|
|---|
| 96 | buf = Buffer.from('.\r\n');
|
|---|
| 97 | } else if (this.lastByte === 0x0d) {
|
|---|
| 98 | buf = Buffer.from('\n.\r\n');
|
|---|
| 99 | } else {
|
|---|
| 100 | buf = Buffer.from('\r\n.\r\n');
|
|---|
| 101 | }
|
|---|
| 102 | this.outByteCount += buf.length;
|
|---|
| 103 | this.push(buf);
|
|---|
| 104 | done();
|
|---|
| 105 | }
|
|---|
| 106 | }
|
|---|
| 107 |
|
|---|
| 108 | module.exports = DataStream;
|
|---|