@foliojs-fork/restructure
Version:
Declaratively encode and decode binary data
126 lines (107 loc) • 3.24 kB
JavaScript
let iconv;
const stream = require('stream');
const DecodeStream = require('./DecodeStream');
try { iconv = require('iconv-lite'); } catch (error) {}
class EncodeStream extends stream.Readable {
constructor(bufferSize = 65536) {
super(...arguments);
this.buffer = Buffer.alloc(bufferSize);
this.bufferOffset = 0;
this.pos = 0;
}
// do nothing, required by node
_read() {}
ensure(bytes) {
if ((this.bufferOffset + bytes) > this.buffer.length) {
return this.flush();
}
}
flush() {
if (this.bufferOffset > 0) {
this.push(Buffer.from(this.buffer.slice(0, this.bufferOffset)));
return this.bufferOffset = 0;
}
}
writeBuffer(buffer) {
this.flush();
this.push(buffer);
return this.pos += buffer.length;
}
writeString(string, encoding = 'ascii') {
switch (encoding) {
case 'utf16le': case 'ucs2': case 'utf8': case 'ascii':
return this.writeBuffer(Buffer.from(string, encoding));
case 'utf16be':
var buf = Buffer.from(string, 'utf16le');
// swap the bytes
for (let i = 0, end = buf.length - 1; i < end; i += 2) {
const byte = buf[i];
buf[i] = buf[i + 1];
buf[i + 1] = byte;
}
return this.writeBuffer(buf);
default:
if (iconv) {
return this.writeBuffer(iconv.encode(string, encoding));
} else {
throw new Error('Install iconv-lite to enable additional string encodings.');
}
}
}
writeUInt24BE(val) {
this.ensure(3);
this.buffer[this.bufferOffset++] = (val >>> 16) & 0xff;
this.buffer[this.bufferOffset++] = (val >>> 8) & 0xff;
this.buffer[this.bufferOffset++] = val & 0xff;
return this.pos += 3;
}
writeUInt24LE(val) {
this.ensure(3);
this.buffer[this.bufferOffset++] = val & 0xff;
this.buffer[this.bufferOffset++] = (val >>> 8) & 0xff;
this.buffer[this.bufferOffset++] = (val >>> 16) & 0xff;
return this.pos += 3;
}
writeInt24BE(val) {
if (val >= 0) {
return this.writeUInt24BE(val);
} else {
return this.writeUInt24BE(val + 0xffffff + 1);
}
}
writeInt24LE(val) {
if (val >= 0) {
return this.writeUInt24LE(val);
} else {
return this.writeUInt24LE(val + 0xffffff + 1);
}
}
fill(val, length) {
if (length < this.buffer.length) {
this.ensure(length);
this.buffer.fill(val, this.bufferOffset, this.bufferOffset + length);
this.bufferOffset += length;
return this.pos += length;
} else {
const buf = Buffer.alloc(length);
buf.fill(val);
return this.writeBuffer(buf);
}
}
end() {
this.flush();
return this.push(null);
}
}
for (let key in Buffer.prototype) {
if (key.slice(0, 5) === 'write') {
const bytes = +DecodeStream.TYPES[key.replace(/write|[BL]E/g, '')];
EncodeStream.prototype[key] = function(value) {
this.ensure(bytes);
this.buffer[key](value, this.bufferOffset);
this.bufferOffset += bytes;
return this.pos += bytes;
};
}
}
module.exports = EncodeStream;