@narumir/amf
Version:
Action Message Format for nodejs
367 lines (276 loc) • 8.33 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.AMF0Serialize = void 0;
var _constants = require("./constants");
class AMF0Serialize {
buffer = Buffer.alloc(0);
references = [];
constructor(data) {
this.writeData(data);
}
getResult() {
return this.buffer;
}
writeNumberMarker(data) {
this.writeUInt8(_constants.AMF0DataType.NUMBER_MARKER);
const buf = Buffer.alloc(8);
buf.writeDoubleBE(data);
this.buffer = Buffer.concat([this.buffer, buf]);
}
writeBooleanMarker(data) {
this.writeUInt8(_constants.AMF0DataType.BOOLEAN_MARKER);
const buf = Buffer.alloc(1, 0);
buf.writeUint8(data ? 1 : 0);
this.buffer = Buffer.concat([this.buffer, buf]);
}
writeStringMarker(data, withMarker = true) {
if (withMarker) {
this.writeUInt8(_constants.AMF0DataType.STRING_MARKER);
}
const buf = Buffer.from(data);
this.writeUInt16(buf.length);
this.buffer = Buffer.concat([this.buffer, buf]);
}
writeObjectMarker(data) {
this.writeUInt8(_constants.AMF0DataType.OBJECT_MARKER);
for (let key in data) {
this.writeStringMarker(key, false);
this.writeData(data[key]);
}
this.writeStringMarker("", false);
this.writeObjectEndMarker();
}
writeNullMarker() {
this.writeUInt8(_constants.AMF0DataType.NULL_MARKER);
}
writeUndefinedMarker() {
this.writeUInt8(_constants.AMF0DataType.UNDEFINED_MARKER);
}
writeReferenceMarker(data) {
this.writeUInt8(_constants.AMF0DataType.REFERENCE_MARKER);
const idx = this.references.indexOf(data);
if (idx === -1) {
this.references.push(data);
}
if (idx > _constants.AMF0_NORMAL_MAX_SIZE) {
throw new Error("Out of Reference range.");
}
this.writeUInt16(idx);
}
writeECMAArrayMarker(data) {
const idx = this.references.indexOf(data);
if (idx >= 0) {
this.writeReferenceMarker(data);
}
this.references.push(data);
this.writeUInt8(_constants.AMF0DataType.ECMA_ARRAY_MARKER);
this.writeUInt32(data.length);
for (const key in data) {
this.writeStringMarker(key, false);
this.writeData(data[key]);
}
this.writeUInt16(0);
this.writeUInt8(_constants.AMF0DataType.OBJECT_END_MARKER);
}
writeObjectEndMarker() {
this.writeUInt8(_constants.AMF0DataType.OBJECT_END_MARKER);
}
writeStrictArrayMarker(data) {
const idx = this.references.indexOf(data);
if (idx >= 0) {
this.writeReferenceMarker(data);
}
this.references.push(data);
this.writeUInt8(_constants.AMF0DataType.STRICT_ARRAY_MARKER);
this.writeUInt32(data.length);
for (const key in data) {
this.writeStringMarker(key, false);
this.writeData(data[key]);
}
this.writeUInt16(0);
this.writeUInt8(_constants.AMF0DataType.OBJECT_END_MARKER);
}
writeDateMarker(data) {
this.writeUInt8(_constants.AMF0DataType.DATE_MARKER);
this.writeNumberMarker(data.getTime());
this.writeUInt16(0);
}
writeLongStringMarker(data, withMarker = true) {
if (withMarker) {
this.writeUInt8(_constants.AMF0DataType.LONG_STRING_MARKER);
}
const buf = Buffer.from(data);
this.writeUInt16(buf.length);
this.buffer = Buffer.concat([this.buffer, buf]);
}
writeUnsupportMarker() {
this.writeUInt8(_constants.AMF0DataType.UNSUPPORT_MARKER);
}
writeXMLDocumentMarker(data) {
this.writeUInt8(_constants.AMF0DataType.XML_DOCUMENT_MARKER);
this.writeLongStringMarker(data, false);
}
writeTypedObjectMarker(data) {
const idx = this.references.indexOf(data);
if (idx >= 0) {
this.writeReferenceMarker(data);
}
this.references.push(data);
this.writeUInt8(_constants.AMF0DataType.TYPED_OBJECT_MARKER);
this.writeStringMarker(data.constructor.name, false);
for (const key in data) {
this.writeStringMarker(key, false);
this.writeData(data[key]);
}
this.writeUInt16(0);
this.writeUInt8(_constants.AMF0DataType.OBJECT_END_MARKER);
}
writeData(data) {
if (data == null) {
throw new Error("Unknown data.");
}
if (data.marker == null) {
return this.writeWithoutMarker(data);
}
switch (data.marker) {
case _constants.AMF0Marker.NUMBER:
if (typeof data.value !== "number") {
break;
}
return this.writeNumberMarker(data.value);
case _constants.AMF0Marker.BOOLEAN:
if (typeof data.value !== "boolean") {
break;
}
return this.writeBooleanMarker(data.value);
case _constants.AMF0Marker.STRING:
if (typeof data.value !== "string") {
break;
}
const str = data.value;
return str.length > _constants.AMF0_NORMAL_MAX_SIZE ? this.writeLongStringMarker(str) : this.writeStringMarker(str);
case _constants.AMF0Marker.OBJECT:
if (!this.isObject(data.value)) {
break;
}
return this.writeObjectMarker(data.value);
case _constants.AMF0Marker.NULL:
return this.writeNullMarker();
case _constants.AMF0Marker.UNDEFINED:
return this.writeUndefinedMarker();
case _constants.AMF0Marker.ECMA_ARRAY:
return this.writeECMAArrayMarker(data.value);
case _constants.AMF0Marker.STRICT_ARRAY:
return this.writeStrictArrayMarker(data.value);
case _constants.AMF0Marker.DATE:
if (data.value instanceof Date === false) {
break;
}
return this.writeDateMarker(data.value);
case _constants.AMF0Marker.XML_DOCUMENT:
if (typeof data.value !== "string") {
break;
}
return this.writeXMLDocumentMarker(data.value);
case _constants.AMF0Marker.TYPED_OBJECT:
if (!this.isTypedObject(data.value)) {
break;
}
return this.writeTypedObjectMarker(data.value);
case _constants.AMF0Marker.AVM_PLUS_OBJECT:
// TODO
return;
default:
throw new TypeError("Unknown AMF types.");
}
return this.writeUnsupportMarker();
}
writeWithoutMarker(data) {
if (data === null) {
return this.writeNullMarker();
}
if (data === undefined) {
return this.writeUndefinedMarker();
}
if (typeof data === "number") {
return this.writeNumberMarker(data);
}
if (typeof data === "boolean") {
return this.writeBooleanMarker(data);
}
if (typeof data === "string") {
return data.length > _constants.AMF0_NORMAL_MAX_SIZE ? this.writeLongStringMarker(data) : this.writeStringMarker(data);
}
if (data instanceof Date) {
return this.writeDateMarker(data);
}
if (Array.isArray(data)) {
return this.isStrictArray(data) ? this.writeStrictArrayMarker(data) : this.writeECMAArrayMarker(data);
}
if (this.isObject(data)) {
return this.writeObjectMarker(data);
}
if (this.isTypedObject(data)) {
return this.writeTypedObjectMarker(data);
}
return this.writeUnsupportMarker();
}
writeUInt8(data) {
const buf = Buffer.alloc(1, 0);
buf.writeUint8(data);
this.buffer = Buffer.concat([this.buffer, buf]);
}
writeUInt16(data) {
const buf = Buffer.alloc(2, 0);
buf.writeUint16BE(data);
this.buffer = Buffer.concat([this.buffer, buf]);
}
writeUInt32(data) {
const buf = Buffer.alloc(4, 0);
buf.writeUint32BE(data);
this.buffer = Buffer.concat([this.buffer, buf]);
}
isObject(data) {
if (data == null) {
return false;
}
if (typeof data !== "object") {
return false;
}
if (data instanceof Date) {
return false;
}
if (data.constructor.name !== "Object") {
return false;
}
return true;
}
isTypedObject(data) {
if (data == null) {
return false;
}
if (typeof data !== "object") {
return false;
}
if (data instanceof Date) {
return false;
}
if (data.constructor.name === "Object") {
return false;
}
return true;
}
isStrictArray(data) {
let length = 0;
for (const _ in data) {
length += 1;
}
if (data.length !== length) {
return false;
}
return true;
}
}
exports.AMF0Serialize = AMF0Serialize;