130 lines
3.1 KiB
JavaScript
130 lines
3.1 KiB
JavaScript
import {DecodeStream} from './DecodeStream.js';
|
|
|
|
const textEncoder = new TextEncoder();
|
|
const isBigEndian = new Uint8Array(new Uint16Array([0x1234]).buffer)[0] == 0x12;
|
|
|
|
export class EncodeStream {
|
|
constructor(buffer) {
|
|
this.buffer = buffer;
|
|
this.view = new DataView(this.buffer.buffer, this.buffer.byteOffset, this.buffer.byteLength);
|
|
this.pos = 0;
|
|
}
|
|
|
|
writeBuffer(buffer) {
|
|
this.buffer.set(buffer, this.pos);
|
|
this.pos += buffer.length;
|
|
}
|
|
|
|
writeString(string, encoding = 'ascii') {
|
|
let buf;
|
|
switch (encoding) {
|
|
case 'utf16le':
|
|
case 'utf16-le':
|
|
case 'ucs2': // node treats this the same as utf16.
|
|
buf = stringToUtf16(string, isBigEndian);
|
|
break;
|
|
|
|
case 'utf16be':
|
|
case 'utf16-be':
|
|
buf = stringToUtf16(string, !isBigEndian);
|
|
break;
|
|
|
|
case 'utf8':
|
|
buf = textEncoder.encode(string);
|
|
break;
|
|
|
|
case 'ascii':
|
|
buf = stringToAscii(string);
|
|
break;
|
|
|
|
default:
|
|
throw new Error(`Unsupported encoding: ${encoding}`);
|
|
}
|
|
|
|
this.writeBuffer(buf);
|
|
}
|
|
|
|
writeUInt24BE(val) {
|
|
this.buffer[this.pos++] = (val >>> 16) & 0xff;
|
|
this.buffer[this.pos++] = (val >>> 8) & 0xff;
|
|
this.buffer[this.pos++] = val & 0xff;
|
|
}
|
|
|
|
writeUInt24LE(val) {
|
|
this.buffer[this.pos++] = val & 0xff;
|
|
this.buffer[this.pos++] = (val >>> 8) & 0xff;
|
|
this.buffer[this.pos++] = (val >>> 16) & 0xff;
|
|
}
|
|
|
|
writeInt24BE(val) {
|
|
if (val >= 0) {
|
|
this.writeUInt24BE(val);
|
|
} else {
|
|
this.writeUInt24BE(val + 0xffffff + 1);
|
|
}
|
|
}
|
|
|
|
writeInt24LE(val) {
|
|
if (val >= 0) {
|
|
this.writeUInt24LE(val);
|
|
} else {
|
|
this.writeUInt24LE(val + 0xffffff + 1);
|
|
}
|
|
}
|
|
|
|
fill(val, length) {
|
|
if (length < this.buffer.length) {
|
|
this.buffer.fill(val, this.pos, this.pos + length);
|
|
this.pos += length;
|
|
} else {
|
|
const buf = new Uint8Array(length);
|
|
buf.fill(val);
|
|
this.writeBuffer(buf);
|
|
}
|
|
}
|
|
}
|
|
|
|
function stringToUtf16(string, swap) {
|
|
let buf = new Uint16Array(string.length);
|
|
for (let i = 0; i < string.length; i++) {
|
|
let code = string.charCodeAt(i);
|
|
if (swap) {
|
|
code = (code >> 8) | ((code & 0xff) << 8);
|
|
}
|
|
buf[i] = code;
|
|
}
|
|
return new Uint8Array(buf.buffer);
|
|
}
|
|
|
|
function stringToAscii(string) {
|
|
let buf = new Uint8Array(string.length);
|
|
for (let i = 0; i < string.length; i++) {
|
|
// Match node.js behavior - encoding allows 8-bit rather than 7-bit.
|
|
buf[i] = string.charCodeAt(i);
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
for (let key of Object.getOwnPropertyNames(DataView.prototype)) {
|
|
if (key.slice(0, 3) === 'set') {
|
|
let type = key.slice(3).replace('Ui', 'UI');
|
|
if (type === 'Float32') {
|
|
type = 'Float';
|
|
} else if (type === 'Float64') {
|
|
type = 'Double';
|
|
}
|
|
let bytes = DecodeStream.TYPES[type];
|
|
EncodeStream.prototype['write' + type + (bytes === 1 ? '' : 'BE')] = function (value) {
|
|
this.view[key](this.pos, value, false);
|
|
this.pos += bytes;
|
|
};
|
|
|
|
if (bytes !== 1) {
|
|
EncodeStream.prototype['write' + type + 'LE'] = function (value) {
|
|
this.view[key](this.pos, value, true);
|
|
this.pos += bytes;
|
|
};
|
|
}
|
|
}
|
|
}
|