Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@qnighy/marshal

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@qnighy/marshal - npm Package Compare versions

Comparing version 0.1.1 to 0.1.2

dist/error.d.ts

9

CHANGELOG.md
## Unreleased
## 0.1.2
- `parse` is now available as `Marshal.parse` too https://github.com/qnighy/marshal-js/pull/2
- Misc
- Promote `@types/node` to `dependencies` https://github.com/qnighy/marshal-js/pull/3
- Refactor modules https://github.com/qnighy/marshal-js/pull/2
## 0.1.1
- Use `defineProperty` to construct hashes.
- Use `defineProperty` to construct hashes. https://github.com/qnighy/marshal-js/pull/1

@@ -7,0 +14,0 @@ ## 0.1.0

446

dist/esm/index.js

@@ -1,442 +0,4 @@

import _createClass from "@babel/runtime-corejs3/helpers/createClass";
import _defineProperty from "@babel/runtime-corejs3/helpers/defineProperty";
import _classCallCheck from "@babel/runtime-corejs3/helpers/classCallCheck";
import _inherits from "@babel/runtime-corejs3/helpers/inherits";
import _createSuper from "@babel/runtime-corejs3/helpers/createSuper";
import _wrapNativeSuper from "@babel/runtime-corejs3/helpers/wrapNativeSuper";
import _concatInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/concat";
import _sliceInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/slice";
/**
* An exception raised when `loadMarshal` encountered an invalid format.
*/
export var MarshalError = /*#__PURE__*/function (_Error) {
_inherits(MarshalError, _Error);
var _super = _createSuper(MarshalError);
function MarshalError() {
var message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "";
_classCallCheck(this, MarshalError);
return _super.call(this, "Marshal error: ".concat(message));
}
return MarshalError;
}( /*#__PURE__*/_wrapNativeSuper(Error));
/**
* Parses a data exported by Ruby's `Marshal.load`.
* @param buf A binary data to parse
* @returns the decoded value
* @throws {MarshalError} when the data contains an invalid format.
*/
export function parse(buf) {
return new Parser(buf).read();
}
var Parser = /*#__PURE__*/function () {
function Parser(buf) {
var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
_classCallCheck(this, Parser);
_defineProperty(this, "symbols", []);
_defineProperty(this, "objects", []);
this.buf = buf;
this.index = index;
this.buf = Buffer.from(this.buf);
}
_createClass(Parser, [{
key: "read",
value: function read() {
this.symbols = [];
this.objects = [];
var major = this.readByte();
var minor = this.readByte();
if (major !== 4 || minor > 8) {
var _context;
throw new MarshalError(_concatInstanceProperty(_context = "incompatible marshal file format (can't be read): format version 4.8 required; ".concat(major, ".")).call(_context, minor, " given"));
}
return this.readAny();
}
}, {
key: "readAny",
value: function readAny() {
var tag = this.readByte();
switch (tag) {
// '"': an instance of String
case 0x22:
return this.entry(this.readString());
// '/': an instance of Regexp
case 0x2f:
{
var source = this.readString(); // Discard flags
this.readByte();
return this.entry(new RegExp(source));
}
// '0': nil
case 0x30:
return null;
// ':': an instance of Symbol
case 0x3a:
{
var sym = this.readString();
this.symbols.push(sym);
return sym;
}
// ';': symbol reference
case 0x3b:
{
var symref = this.readInt();
if (symref < 0 || symref >= this.symbols.length) {
throw new MarshalError("bad symbol");
}
return this.symbols[symref];
}
// '@': an object link
case 0x40:
{
var objref = this.readInt();
if (objref < 0 || objref >= this.objects.length) {
throw new MarshalError("dump format error (unlinked)");
}
return this.objects[objref];
}
// 'C': an instance of String/Regexp/Array/Hash subclass
case 0x43:
{
// Discard class name
this.readAny();
return this.readAny();
}
// 'F': false
case 0x46:
return false;
// 'I': add instance variables
case 0x49:
{
var obj = this.readAny();
var length = this.readInt();
for (var i = 0; i < length; i++) {
// Discard instance variables
this.readAny();
this.readAny();
}
return obj;
}
// 'M': a module or class (old format)
case 0x4d:
{
// Discard class/module name
this.readBytes();
return this.entry({});
}
// 'S': an instance of a struct
case 0x53:
{
// Discard class name
this.readAny();
var _length = this.readLength("struct");
var struct = this.entry({});
for (var _i = 0; _i < _length; _i++) {
var key = this.readAny();
var value = this.readAny(); // Discard non-String keys
if (typeof key === "number" || typeof key === "string") {
Object.defineProperty(struct, key, {
value: value,
writable: true,
configurable: true,
enumerable: true
});
}
}
return struct;
}
// 'T': true
case 0x54:
return true;
// 'U': custom format (marshal_dump)
case 0x55:
{
// Discard class name
this.readAny();
var _obj = this.entry({}); // Discard data
this.readAny();
return _obj;
}
// '[': an instance of Array
case 0x5b:
{
var _length2 = this.readLength("array");
var arr = this.entry([]);
for (var _i2 = 0; _i2 < _length2; _i2++) {
arr.push(this.readAny());
}
return arr;
}
// 'c': a class
case 0x63:
{
// Discard class name
this.readBytes();
return this.entry({});
}
// 'd': TYPE_DATA
case 0x64:
throw new MarshalError("unimplemented: TYPE_DATA");
// 'e': TYPE_EXTENDED
case 0x65:
throw new MarshalError("unimplemented: TYPE_EXTENDED");
// 'f': an instance of Float
case 0x66:
{
var s = this.readString();
var f = s === "inf" ? Infinity : s === "-inf" ? -Infinity : s === "nan" ? NaN : parseFloat(s);
return this.entry(f);
}
// 'i': an instance of Integer (small)
case 0x69:
return this.readInt();
// 'l': an instance of Integer (large)
case 0x6c:
{
var signChar = this.readByte();
var _length3 = this.readLength("string") * 2;
var sum = 0;
var magnitude = signChar === 0x2d ? -1 : 1;
for (var _i3 = 0; _i3 < _length3; _i3++) {
sum += this.readByte() * magnitude;
magnitude *= 256;
}
return this.entry(sum);
}
// 'm': a module
case 0x6d:
{
// Discard module name
this.readBytes();
return this.entry({});
}
// 'o': a plain object
case 0x6f:
{
// Discard class name
this.readAny();
var _obj2 = this.entry({});
var _length4 = this.readInt();
for (var _i4 = 0; _i4 < _length4; _i4++) {
// Discard instance variables
this.readAny();
this.readAny();
}
return _obj2;
}
// 'u': old custom format (_dump)
case 0x75:
{
// Discard class name
this.readAny(); // Discard data
this.readBytes();
return this.entry({});
}
// '{': an instance of Hash (without default value)
case 0x7b:
{
var _length5 = this.readLength("hash");
var hash = this.entry({});
for (var _i5 = 0; _i5 < _length5; _i5++) {
var _key = this.readAny();
var _value = this.readAny(); // Discard non-String keys
if (typeof _key === "number" || typeof _key === "string") {
Object.defineProperty(hash, _key, {
value: _value,
writable: true,
configurable: true,
enumerable: true
});
}
}
return hash;
}
// '}': an instance of Hash (with default value)
case 0x7d:
{
var _length6 = this.readLength("hash");
var _hash = this.entry({});
for (var _i6 = 0; _i6 < _length6; _i6++) {
var _key2 = this.readAny();
var _value2 = this.readAny(); // Discard non-String keys
if (typeof _key2 === "number" || typeof _key2 === "string") {
Object.defineProperty(_hash, _key2, {
value: _value2,
writable: true,
configurable: true,
enumerable: true
});
}
}
_hash["__ruby_default"] = this.readAny();
return _hash;
}
default:
throw new MarshalError("dump format error(0x".concat(tag.toString(16), ")"));
}
}
}, {
key: "readLength",
value: function readLength(msg) {
var length = this.readInt();
if (length < 0) {
throw new MarshalError("negative ".concat(msg, " size (or size too big)"));
}
return length;
}
}, {
key: "readInt",
value: function readInt() {
var tag = this.readByte();
if (tag === 0) {
return 0;
}
if (tag >= 5 && tag < 128) {
return tag - 5;
}
if (tag >= 128 && tag <= 251) {
return tag - 251;
}
var length = tag < 128 ? tag : 256 - tag;
var sum = 0;
var magnitude = 1;
for (var i = 0; i < length; i++) {
sum += magnitude * this.readByte();
magnitude *= 256;
}
if (tag >= 128) {
sum -= magnitude;
}
return sum;
}
}, {
key: "readByte",
value: function readByte() {
if (this.index >= this.buf.byteLength) {
throw new MarshalError("marshal data too short");
}
var byte = this.buf.readUInt8(this.index);
this.index++;
return byte;
}
}, {
key: "readString",
value: function readString() {
return this.readBytes().toString("utf-8");
}
}, {
key: "readBytes",
value: function readBytes() {
var _context2;
var length = this.readLength("string");
if (this.index + length > this.buf.byteLength) {
throw new MarshalError("marshal data too short");
}
var bytes = _sliceInstanceProperty(_context2 = this.buf).call(_context2, this.index, this.index + length);
this.index += length;
return bytes;
}
}, {
key: "entry",
value: function entry(obj) {
this.objects.push(obj);
return obj;
}
}]);
return Parser;
}();
export { MarshalError } from "./error";
export { parse } from "./parse";
import * as _Marshal from "./marshal-object";
export { _Marshal as Marshal };

@@ -1,14 +0,3 @@

/// <reference types="node" />
/**
* An exception raised when `loadMarshal` encountered an invalid format.
*/
export declare class MarshalError extends Error {
constructor(message?: string);
}
/**
* Parses a data exported by Ruby's `Marshal.load`.
* @param buf A binary data to parse
* @returns the decoded value
* @throws {MarshalError} when the data contains an invalid format.
*/
export declare function parse(buf: Buffer): unknown;
export { MarshalError } from "./error";
export { parse } from "./parse";
export * as Marshal from "./marshal-object";
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
var _interopRequireWildcard = require("@babel/runtime-corejs3/helpers/interopRequireWildcard").default;

@@ -8,448 +8,22 @@ Object.defineProperty(exports, "__esModule", {

});
exports.parse = parse;
exports.MarshalError = void 0;
var _concat = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/concat"));
var _slice = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/slice"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/createClass"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/defineProperty"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/classCallCheck"));
var _inherits2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/inherits"));
var _createSuper2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/createSuper"));
var _wrapNativeSuper2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/wrapNativeSuper"));
/**
* An exception raised when `loadMarshal` encountered an invalid format.
*/
var MarshalError = /*#__PURE__*/function (_Error) {
(0, _inherits2.default)(MarshalError, _Error);
var _super = (0, _createSuper2.default)(MarshalError);
function MarshalError() {
var message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "";
(0, _classCallCheck2.default)(this, MarshalError);
return _super.call(this, "Marshal error: ".concat(message));
Object.defineProperty(exports, "MarshalError", {
enumerable: true,
get: function get() {
return _error.MarshalError;
}
return MarshalError;
}( /*#__PURE__*/(0, _wrapNativeSuper2.default)(Error));
/**
* Parses a data exported by Ruby's `Marshal.load`.
* @param buf A binary data to parse
* @returns the decoded value
* @throws {MarshalError} when the data contains an invalid format.
*/
exports.MarshalError = MarshalError;
function parse(buf) {
return new Parser(buf).read();
}
var Parser = /*#__PURE__*/function () {
function Parser(buf) {
var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
(0, _classCallCheck2.default)(this, Parser);
(0, _defineProperty2.default)(this, "symbols", []);
(0, _defineProperty2.default)(this, "objects", []);
this.buf = buf;
this.index = index;
this.buf = Buffer.from(this.buf);
});
Object.defineProperty(exports, "parse", {
enumerable: true,
get: function get() {
return _parse.parse;
}
});
exports.Marshal = void 0;
(0, _createClass2.default)(Parser, [{
key: "read",
value: function read() {
this.symbols = [];
this.objects = [];
var major = this.readByte();
var minor = this.readByte();
var _error = require("./error");
if (major !== 4 || minor > 8) {
var _context;
var _parse = require("./parse");
throw new MarshalError((0, _concat.default)(_context = "incompatible marshal file format (can't be read): format version 4.8 required; ".concat(major, ".")).call(_context, minor, " given"));
}
var _Marshal = _interopRequireWildcard(require("./marshal-object"));
return this.readAny();
}
}, {
key: "readAny",
value: function readAny() {
var tag = this.readByte();
switch (tag) {
// '"': an instance of String
case 0x22:
return this.entry(this.readString());
// '/': an instance of Regexp
case 0x2f:
{
var source = this.readString(); // Discard flags
this.readByte();
return this.entry(new RegExp(source));
}
// '0': nil
case 0x30:
return null;
// ':': an instance of Symbol
case 0x3a:
{
var sym = this.readString();
this.symbols.push(sym);
return sym;
}
// ';': symbol reference
case 0x3b:
{
var symref = this.readInt();
if (symref < 0 || symref >= this.symbols.length) {
throw new MarshalError("bad symbol");
}
return this.symbols[symref];
}
// '@': an object link
case 0x40:
{
var objref = this.readInt();
if (objref < 0 || objref >= this.objects.length) {
throw new MarshalError("dump format error (unlinked)");
}
return this.objects[objref];
}
// 'C': an instance of String/Regexp/Array/Hash subclass
case 0x43:
{
// Discard class name
this.readAny();
return this.readAny();
}
// 'F': false
case 0x46:
return false;
// 'I': add instance variables
case 0x49:
{
var obj = this.readAny();
var length = this.readInt();
for (var i = 0; i < length; i++) {
// Discard instance variables
this.readAny();
this.readAny();
}
return obj;
}
// 'M': a module or class (old format)
case 0x4d:
{
// Discard class/module name
this.readBytes();
return this.entry({});
}
// 'S': an instance of a struct
case 0x53:
{
// Discard class name
this.readAny();
var _length = this.readLength("struct");
var struct = this.entry({});
for (var _i = 0; _i < _length; _i++) {
var key = this.readAny();
var value = this.readAny(); // Discard non-String keys
if (typeof key === "number" || typeof key === "string") {
Object.defineProperty(struct, key, {
value: value,
writable: true,
configurable: true,
enumerable: true
});
}
}
return struct;
}
// 'T': true
case 0x54:
return true;
// 'U': custom format (marshal_dump)
case 0x55:
{
// Discard class name
this.readAny();
var _obj = this.entry({}); // Discard data
this.readAny();
return _obj;
}
// '[': an instance of Array
case 0x5b:
{
var _length2 = this.readLength("array");
var arr = this.entry([]);
for (var _i2 = 0; _i2 < _length2; _i2++) {
arr.push(this.readAny());
}
return arr;
}
// 'c': a class
case 0x63:
{
// Discard class name
this.readBytes();
return this.entry({});
}
// 'd': TYPE_DATA
case 0x64:
throw new MarshalError("unimplemented: TYPE_DATA");
// 'e': TYPE_EXTENDED
case 0x65:
throw new MarshalError("unimplemented: TYPE_EXTENDED");
// 'f': an instance of Float
case 0x66:
{
var s = this.readString();
var f = s === "inf" ? Infinity : s === "-inf" ? -Infinity : s === "nan" ? NaN : parseFloat(s);
return this.entry(f);
}
// 'i': an instance of Integer (small)
case 0x69:
return this.readInt();
// 'l': an instance of Integer (large)
case 0x6c:
{
var signChar = this.readByte();
var _length3 = this.readLength("string") * 2;
var sum = 0;
var magnitude = signChar === 0x2d ? -1 : 1;
for (var _i3 = 0; _i3 < _length3; _i3++) {
sum += this.readByte() * magnitude;
magnitude *= 256;
}
return this.entry(sum);
}
// 'm': a module
case 0x6d:
{
// Discard module name
this.readBytes();
return this.entry({});
}
// 'o': a plain object
case 0x6f:
{
// Discard class name
this.readAny();
var _obj2 = this.entry({});
var _length4 = this.readInt();
for (var _i4 = 0; _i4 < _length4; _i4++) {
// Discard instance variables
this.readAny();
this.readAny();
}
return _obj2;
}
// 'u': old custom format (_dump)
case 0x75:
{
// Discard class name
this.readAny(); // Discard data
this.readBytes();
return this.entry({});
}
// '{': an instance of Hash (without default value)
case 0x7b:
{
var _length5 = this.readLength("hash");
var hash = this.entry({});
for (var _i5 = 0; _i5 < _length5; _i5++) {
var _key = this.readAny();
var _value = this.readAny(); // Discard non-String keys
if (typeof _key === "number" || typeof _key === "string") {
Object.defineProperty(hash, _key, {
value: _value,
writable: true,
configurable: true,
enumerable: true
});
}
}
return hash;
}
// '}': an instance of Hash (with default value)
case 0x7d:
{
var _length6 = this.readLength("hash");
var _hash = this.entry({});
for (var _i6 = 0; _i6 < _length6; _i6++) {
var _key2 = this.readAny();
var _value2 = this.readAny(); // Discard non-String keys
if (typeof _key2 === "number" || typeof _key2 === "string") {
Object.defineProperty(_hash, _key2, {
value: _value2,
writable: true,
configurable: true,
enumerable: true
});
}
}
_hash["__ruby_default"] = this.readAny();
return _hash;
}
default:
throw new MarshalError("dump format error(0x".concat(tag.toString(16), ")"));
}
}
}, {
key: "readLength",
value: function readLength(msg) {
var length = this.readInt();
if (length < 0) {
throw new MarshalError("negative ".concat(msg, " size (or size too big)"));
}
return length;
}
}, {
key: "readInt",
value: function readInt() {
var tag = this.readByte();
if (tag === 0) {
return 0;
}
if (tag >= 5 && tag < 128) {
return tag - 5;
}
if (tag >= 128 && tag <= 251) {
return tag - 251;
}
var length = tag < 128 ? tag : 256 - tag;
var sum = 0;
var magnitude = 1;
for (var i = 0; i < length; i++) {
sum += magnitude * this.readByte();
magnitude *= 256;
}
if (tag >= 128) {
sum -= magnitude;
}
return sum;
}
}, {
key: "readByte",
value: function readByte() {
if (this.index >= this.buf.byteLength) {
throw new MarshalError("marshal data too short");
}
var byte = this.buf.readUInt8(this.index);
this.index++;
return byte;
}
}, {
key: "readString",
value: function readString() {
return this.readBytes().toString("utf-8");
}
}, {
key: "readBytes",
value: function readBytes() {
var _context2;
var length = this.readLength("string");
if (this.index + length > this.buf.byteLength) {
throw new MarshalError("marshal data too short");
}
var bytes = (0, _slice.default)(_context2 = this.buf).call(_context2, this.index, this.index + length);
this.index += length;
return bytes;
}
}, {
key: "entry",
value: function entry(obj) {
this.objects.push(obj);
return obj;
}
}]);
return Parser;
}();
exports.Marshal = _Marshal;
{
"name": "@qnighy/marshal",
"description": "Decoder for Ruby's Marshal",
"version": "0.1.1",
"version": "0.1.2",
"license": "MIT",

@@ -17,3 +17,6 @@ "homepage": "https://github.com/qnighy/marshal-js",

"dist/**",
"src/index.ts"
"src/error.ts",
"src/index.ts",
"src/marshal-object.ts",
"src/parse.ts"
],

@@ -35,3 +38,4 @@ "scripts": {

"dependencies": {
"@babel/runtime-corejs3": "^7.14.9"
"@babel/runtime-corejs3": "^7.14.9",
"@types/node": "^16.4.11"
},

@@ -45,3 +49,2 @@ "devDependencies": {

"@jest/globals": "^27.0.6",
"@types/node": "^16.4.11",
"@typescript-eslint/eslint-plugin": "^4.29.0",

@@ -48,0 +51,0 @@ "@typescript-eslint/parser": "^4.29.0",

@@ -14,14 +14,11 @@ ## `@qnighy/marshal`

```javascript
import * as Marshal from "@qnighy/marshal";
import { Marshal } from "@qnighy/marshal";
// OR
const Marshal = require("@qnighy/marshal");
const { Marshal } = require("@qnighy/marshal");
const buf = Buffer.from(
[
4, 8, 123, 7, 58, 9, 110, 97, 109, 101,
73, 34, 8, 102, 111, 111, 6, 58, 6, 69,
84, 58, 12, 110, 117, 109, 98, 101, 114, 115,
91, 8, 105, 6, 105, 7, 105, 8,
]
);
const buf = Buffer.from([
4, 8, 123, 7, 58, 9, 110, 97, 109, 101, 73, 34, 8, 102, 111, 111, 6, 58, 6,
69, 84, 58, 12, 110, 117, 109, 98, 101, 114, 115, 91, 8, 105, 6, 105, 7, 105,
8,
]);
const data = Marshal.parse(buf);

@@ -33,3 +30,3 @@ // => { name: 'foo', numbers: [ 1, 2, 3 ] }

### `function parse`
### `Marshal.parse`

@@ -48,4 +45,8 @@ Parses a data exported by Ruby's `Marshal.load`.

### `class MarshalError`
### `parse`
Same as `Marshal.parse`.
### `MarshalError`
An exception raised when `loadMarshal` encountered an invalid format.

@@ -52,0 +53,0 @@

@@ -1,319 +0,3 @@

/**
* An exception raised when `loadMarshal` encountered an invalid format.
*/
export class MarshalError extends Error {
constructor(message = "") {
super(`Marshal error: ${message}`);
}
}
/**
* Parses a data exported by Ruby's `Marshal.load`.
* @param buf A binary data to parse
* @returns the decoded value
* @throws {MarshalError} when the data contains an invalid format.
*/
export function parse(buf: Buffer): unknown {
return new Parser(buf).read();
}
class Parser {
private symbols: string[] = [];
private objects: unknown[] = [];
constructor(private buf: Buffer, private index = 0) {
this.buf = Buffer.from(this.buf);
}
public read(): unknown {
this.symbols = [];
this.objects = [];
const major = this.readByte();
const minor = this.readByte();
if (major !== 4 || minor > 8) {
throw new MarshalError(
`incompatible marshal file format (can't be read): format version 4.8 required; ${major}.${minor} given`
);
}
return this.readAny();
}
private readAny(): unknown {
const tag = this.readByte();
switch (tag) {
// '"': an instance of String
case 0x22:
return this.entry(this.readString());
// '/': an instance of Regexp
case 0x2f: {
const source = this.readString();
// Discard flags
this.readByte();
return this.entry(new RegExp(source));
}
// '0': nil
case 0x30:
return null;
// ':': an instance of Symbol
case 0x3a: {
const sym = this.readString();
this.symbols.push(sym);
return sym;
}
// ';': symbol reference
case 0x3b: {
const symref = this.readInt();
if (symref < 0 || symref >= this.symbols.length) {
throw new MarshalError("bad symbol");
}
return this.symbols[symref];
}
// '@': an object link
case 0x40: {
const objref = this.readInt();
if (objref < 0 || objref >= this.objects.length) {
throw new MarshalError("dump format error (unlinked)");
}
return this.objects[objref];
}
// 'C': an instance of String/Regexp/Array/Hash subclass
case 0x43: {
// Discard class name
this.readAny();
return this.readAny();
}
// 'F': false
case 0x46:
return false;
// 'I': add instance variables
case 0x49: {
const obj = this.readAny();
const length = this.readInt();
for (let i = 0; i < length; i++) {
// Discard instance variables
this.readAny();
this.readAny();
}
return obj;
}
// 'M': a module or class (old format)
case 0x4d: {
// Discard class/module name
this.readBytes();
return this.entry({});
}
// 'S': an instance of a struct
case 0x53: {
// Discard class name
this.readAny();
const length = this.readLength("struct");
const struct: Record<string, unknown> = this.entry({});
for (let i = 0; i < length; i++) {
const key = this.readAny();
const value = this.readAny();
// Discard non-String keys
if (typeof key === "number" || typeof key === "string") {
Object.defineProperty(struct, key, {
value,
writable: true,
configurable: true,
enumerable: true,
});
}
}
return struct;
}
// 'T': true
case 0x54:
return true;
// 'U': custom format (marshal_dump)
case 0x55: {
// Discard class name
this.readAny();
const obj = this.entry({});
// Discard data
this.readAny();
return obj;
}
// '[': an instance of Array
case 0x5b: {
const length = this.readLength("array");
const arr: unknown[] = this.entry([]);
for (let i = 0; i < length; i++) {
arr.push(this.readAny());
}
return arr;
}
// 'c': a class
case 0x63: {
// Discard class name
this.readBytes();
return this.entry({});
}
// 'd': TYPE_DATA
case 0x64:
throw new MarshalError("unimplemented: TYPE_DATA");
// 'e': TYPE_EXTENDED
case 0x65:
throw new MarshalError("unimplemented: TYPE_EXTENDED");
// 'f': an instance of Float
case 0x66: {
const s = this.readString();
const f =
s === "inf"
? Infinity
: s === "-inf"
? -Infinity
: s === "nan"
? NaN
: parseFloat(s);
return this.entry(f);
}
// 'i': an instance of Integer (small)
case 0x69:
return this.readInt();
// 'l': an instance of Integer (large)
case 0x6c: {
const signChar = this.readByte();
const length = this.readLength("string") * 2;
let sum = 0;
let magnitude = signChar === 0x2d ? -1 : 1;
for (let i = 0; i < length; i++) {
sum += this.readByte() * magnitude;
magnitude *= 256;
}
return this.entry(sum);
}
// 'm': a module
case 0x6d: {
// Discard module name
this.readBytes();
return this.entry({});
}
// 'o': a plain object
case 0x6f: {
// Discard class name
this.readAny();
const obj = this.entry({});
const length = this.readInt();
for (let i = 0; i < length; i++) {
// Discard instance variables
this.readAny();
this.readAny();
}
return obj;
}
// 'u': old custom format (_dump)
case 0x75: {
// Discard class name
this.readAny();
// Discard data
this.readBytes();
return this.entry({});
}
// '{': an instance of Hash (without default value)
case 0x7b: {
const length = this.readLength("hash");
const hash: Record<string, unknown> = this.entry({});
for (let i = 0; i < length; i++) {
const key = this.readAny();
const value = this.readAny();
// Discard non-String keys
if (typeof key === "number" || typeof key === "string") {
Object.defineProperty(hash, key, {
value,
writable: true,
configurable: true,
enumerable: true,
});
}
}
return hash;
}
// '}': an instance of Hash (with default value)
case 0x7d: {
const length = this.readLength("hash");
const hash: Record<string, unknown> = this.entry({});
for (let i = 0; i < length; i++) {
const key = this.readAny();
const value = this.readAny();
// Discard non-String keys
if (typeof key === "number" || typeof key === "string") {
Object.defineProperty(hash, key, {
value,
writable: true,
configurable: true,
enumerable: true,
});
}
}
hash["__ruby_default"] = this.readAny();
return hash;
}
default:
throw new MarshalError(`dump format error(0x${tag.toString(16)})`);
}
}
private readLength(msg: string): number {
const length = this.readInt();
if (length < 0) {
throw new MarshalError(`negative ${msg} size (or size too big)`);
}
return length;
}
private readInt(): number {
const tag = this.readByte();
if (tag === 0) {
return 0;
}
if (tag >= 5 && tag < 128) {
return tag - 5;
}
if (tag >= 128 && tag <= 251) {
return tag - 251;
}
const length = tag < 128 ? tag : 256 - tag;
let sum = 0;
let magnitude = 1;
for (let i = 0; i < length; i++) {
sum += magnitude * this.readByte();
magnitude *= 256;
}
if (tag >= 128) {
sum -= magnitude;
}
return sum;
}
private readByte(): number {
if (this.index >= this.buf.byteLength) {
throw new MarshalError("marshal data too short");
}
const byte = this.buf.readUInt8(this.index);
this.index++;
return byte;
}
private readString(): string {
return this.readBytes().toString("utf-8");
}
private readBytes(): Buffer {
const length = this.readLength("string");
if (this.index + length > this.buf.byteLength) {
throw new MarshalError("marshal data too short");
}
const bytes = this.buf.slice(this.index, this.index + length);
this.index += length;
return bytes;
}
private entry<T>(obj: T): T {
this.objects.push(obj);
return obj;
}
}
export { MarshalError } from "./error";
export { parse } from "./parse";
export * as Marshal from "./marshal-object";
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc