npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@mrhiden/cstruct

v1.5.4

Published

For packing and unpacking bytes (C like structures) in/from Buffer based on Object/Array type for parsing.

Downloads

23

Readme

@mrhiden/cstruct

  • 'C like structures' - TypeScript library

Features

  • Read/make/write buffer, Buffer <=> Object/Array
  • Pack / unpack, compress / decompress data to minimize size.
  • Convert buffer of struct/array to TypeScript object/array and back
  • Able to pin start point from any offset in the buffer (read/write)
  • Can return whole buffer from your data Object/Array (make)
  • Little endian - LE
  • Big endian - BE
  • TypeScript's decorators for classes and properties

Whats new in 1.4 ?

  • Added predefined types
  • Added predefined aliases
  • Fixed issue in one function where we use endian BE -> LE
  • Added more tests to cover that issue and predefined types

Whats new in 1.5 ?

  • Added support for wstring (UTF-16LE) type. Thanks to Sorunome. For wstring/utf16le trailing character is/must be 16bit zero '\u0000'.

Install

npm i @mrhiden/cstruct

Data types, Atom types and aliases

| Atom | Type | Size [B] | Aliases | Notes | |------|--------------------|----------|---------------------------------------------|-------| | b8 | boolean | 1 | bool8 bool BOOL | | | b16 | boolean | 2 | bool16 | | | b32 | boolean | 4 | bool32 | | | b64 | boolean | 8 | bool64 | | | u8 | unsigned char | 1 | uint8 uint8_t BYTE | | | u16 | unsigned int | 2 | uint16 uint16_t WORD | | | u32 | unsigned long | 4 | uint32 uint32_t DWORD | | | u64 | unsigned long long | 8 | uint64 uint64_t LWORD QWORD | | | i8 | signed char | 1 | int8 int8_t SINT | | | i16 | signed int | 2 | int16 int16_t INT | | | i32 | signed long | 4 | int32 int32_t DINT | | | i64 | signed long long | 8 | int64 int64_t LINT QINT | | | f | float | 4 | float float32 float32_t single REAL F F32 | | | d | double | 4 | double float64 float64_t LREAL D F64 | | | sN | string | N | string | N= 0+ | | wsN | wstring (UTF-16LE) | N * 2 | wstring WS WSTR WSTRING | N= 0+ | | bufN | buffer | N | buffer BUF BUFFER | N= 1+ | | jN | json | N | json any J JSON ANY | N= 0+ |

Usage

The main concept is to first create a model of your data structure and then utilize it to read from and write to a buffer.

  1. To achieve this, you can precompile the model and optional types when creating a CStructBE or CStructLE object.
  2. After this step, you can use the object to efficiently access the buffer and perform read/write operations on your data.

For exchanging data between JavaScript and C/C++ you can use the following classes and their methods:

  • CStructBE - Big Endian
  • CStructLE - Little Endian

Both classes uses the same methods and have the same functionality.

Dynamic methods uses Object/Array/String model/types to exchange data. Static methods are designed to use decorators to define model/types.

MAKE When using make method it returns { buffer, offset, size } object. make(struct: T): CStructWriteResult;

WRITE When using write method it returns { buffer, offset, size } object. write(buffer: Buffer, struct: T, offset?: number): CStructWriteResult; Write is different from make because it uses existing buffer and writes data to it. Also write allows to pass offset to pin start point from any offset in the buffer.

READ When using read method it returns { struct, offset, size } object. read<T>(buffer: Buffer, offset?: number): CStructReadResult<T>; Read uses existing buffer and reads data from it. And also read allows to pass offset to pin start point from any offset in the buffer.

OFFSET Offset can be used in different scenario as we want to read/write from/to buffer from any offset. Which allows binary parser to split data into different parts and read/write them separately.

DECORATORS Decorators are used to define model/types for static methods. @CStructClass - defines model/types for class. @CStructProperty - defines type for property.

Static make creates new instance of provided class and fills it with parsed data.

NOTE When using @CStructClass decorator with {model: ... } it can override @CStructProperty decorators.

JavaScript examples

Atomic types instead pure string types

const {CStructBE,CStructLE, hexToBuffer, AtomTypes} = require('@mrhiden/cstruct');
const {U16, I16, STRING} = AtomTypes; // You can also use 'u16', 'i16', 'string' / 's' as before

// JavaScript Example 1
{
    // Model with two fields.
    const model = {a: U16, b: I16}; // = {a: 'u16', b: 'i16'};
    // Create CStruct from model. Precompile.
    const cStruct = CStructBE.fromModelTypes(model);
    // Data to transfer. Make buffer from data. Transfer buffer.
    const data = {a: 10, b: -10};
    // Buffer made.
    const buffer = cStruct.make(data).buffer;
    console.log(buffer.toString('hex'));
    // 000afff6
    // {a: 000a, b: fff6}

    // Read buffer. Receive data.
    const result = cStruct.read(buffer);
    console.log(result.struct);
    // { a: 10, b: -10 }
}

// JavaScript Example 2
{
    // Sensor type. ID and value.
    const types = {
        Sensor: {id: U16, value: I16}, // Sensor: {id: 'u16', value: 'i16'},
    }
    // Model with IOT name and two sensors.
    const model = {
        iotName: STRING(0), // iotName: 's0',
        sensors: 'Sensor[2]',
    };
    // Create CStruct from model and types. Precompile.
    const cStruct = CStructBE.fromModelTypes(model, types);
    // Data to transfer. Make buffer from data. Transfer buffer.
    const data = {
        iotName: 'iot-1',
        sensors: [
            {id: 1, value: -10},
            {id: 2, value: -20}
        ]
    };
    // Buffer made.
    const buffer = cStruct.make(data).buffer;
    console.log(buffer.toString('hex'));
    // 696f742d31000001fff60002ffec
    // '696f742d31'00 [{0001, fff6}, {0002, ffec}]

    // Read buffer. Receive data.
    const result = cStruct.read(buffer);
    console.log(result.struct);
    // { iotName: 'iot-1', sensors: [ { id: 1, value: -10 }, { id: 2, value: -20 } ] }
}

TypeScript examples

Make example

import { CStructBE, CStructProperty } from '@mrhiden/cstruct';

class MyClass {
    @CStructProperty({type: 'u8'})
    public propertyA: number;

    @CStructProperty({type: 'i8'})
    public propertyB: number;
}

const myClass = new MyClass();
myClass.propertyA = 10;
myClass.propertyB = -10;

const bufferMake = CStructBE.make(myClass).buffer;
console.log(bufferMake.toString('hex'));
// 0af6
// 0a f6

Read example

import { CStructBE, CStructProperty } from '@mrhiden/cstruct';

class MyClass {
    @CStructProperty({type: 'u8'})
    public propertyA: number;

    @CStructProperty({type: 'i8'})
    public propertyB: number;
}

const buffer = Buffer.from('0af6', 'hex');
const myClass = CStructBE.read(MyClass, buffer).struct;

console.log(myClass);
// MyClass { propertyA: 10, propertyB: -10 }
console.log(myClass instanceof MyClass);
// true

CStructClass example

import { CStructBE, CStructClass } from '@mrhiden/cstruct';

@CStructClass({
    model: {
        propertyA: 'u8',
        propertyB: 'i8',
    }
})
class MyClass {
    public propertyA: number;
    public propertyB: number;
}

const buffer = Buffer.from('0af6', 'hex');
const myClass = CStructBE.read(MyClass, buffer).struct;

console.log(myClass);
// MyClass { propertyA: 10, propertyB: -10 }
console.log(myClass instanceof MyClass);
// true

Read example with offset, and model and types described as string in CStructClass decorator

import { CStructBE, CStructClass } from '@mrhiden/cstruct';

@CStructClass({
    model: `{propertyA: U8, propertyB: I8}`,
    types: '{U8: uint8, I8: int8}',
})
class MyClass {
    public propertyA: number;
    public propertyB: number;
}

const buffer = Buffer.from('77770af6', 'hex');
const myClass = CStructBE.read(MyClass, buffer, 2).struct;

console.log(myClass);
// MyClass { propertyA: 10, propertyB: -10 }
console.log(myClass instanceof MyClass);
// true

Off course types: '{U8: uint8, I8: int8}' shows only some idea how to use types. Types can be much more complex.

Many examples are in this folder '/examples'

Basic examples

import { CStructBE } from '@mrhiden/cstruct';

// Make BE buffer from struct based on model
const model = { a: 'u16', b: 'i16' };
const cStruct = CStructBE.fromModelTypes(model);

const data = { a: 10, b: -10 };
const buffer = cStruct.make(data).buffer;

console.log(buffer.toString('hex'));
// 000afff6
// 000a fff6
import { CStructBE } from '@mrhiden/cstruct';

// Make BE buffer from struct based on model
const cStruct = CStructBE.fromModelTypes({ error: {code: 'u16', message: 's20'} });

const { buffer, offset, size } = cStruct.make({ error: { code: 10, message: 'xyz' } });

console.log(buffer.toString('hex'));
// 000a78797a0000000000000000000000000000000000
console.log(offset);
// 22
console.log(size);
// 22
import { CStructBE } from '@mrhiden/cstruct';

// Read BE buffer to struct based on model
const buffer = hexToBuffer('000F 6162630000_0000000000_0000000000');
console.log(buffer.toString('hex'));
// 000f616263000000000000000000000000

const cStruct = CStructBE.fromModelTypes({ error: {code: 'u16', message: 's20'} });

const struct = cStruct.read(buffer).struct;

console.log(struct);
// { error: { code: 15, message: 'abc' } }
import { CStructBE } from '@mrhiden/cstruct';

// Read BE buffer to struct based on model
const buffer = hexToBuffer('000F 6162630000_0000000000_0000000000');
console.log(buffer.toString('hex'));
// 000f616263000000000000000000000000

const cStruct = CStructBE.fromModelTypes({ error: {code: 'u16', message: 's20'} });

const { struct, offset, size } = cStruct.read(buffer);

console.log(struct);
// { error: { code: 15, message: 'abc' } }
console.log(offset);
// 17
console.log(size);
// 17

Examples with classes

import { CStructBE } from '@mrhiden/cstruct';

class MyClass {
    public propertyA: number;
    public propertyB: number;
}

const myClass = new MyClass();
myClass.propertyA = 10;
myClass.propertyB = -10;

const cStruct = CStructBE.from({
    model: `{propertyA: U16, propertyB: I16}`,
    types: '{U16: uint16, I16: int16}',
});
const make = cStruct.make(myClass);
console.log(make.buffer.toString('hex'));
// 000afff6
// 000a fff6
import { CStructBE } from '@mrhiden/cstruct';

@CStructClass({
    model: `{propertyA: U16, propertyB: I16}`,
    types: '{U16: uint16, I16: int16}',
})
class MyClass {
    public propertyA: number;
    public propertyB: number;
}

const myClass = new MyClass();
myClass.propertyA = 10;
myClass.propertyB = -10;

const cStruct = CStructBE.from(MyClass);
const make = cStruct.make(myClass);
console.log(make.buffer.toString('hex'));
// 000afff6
// 000a fff6

Examples with types

import { CStructBE } from '@mrhiden/cstruct';

// Model and Types for Sender & Receiver
const types = {
  Sensor: {
    id: 'u32',
    type: 'u8',
    value: 'd',
    timestamp: 'u64',
  }
};
const iotModel = {
  iotName: 's20',
  sensor: 'Sensor',
};

// IOT Sender
const sender = CStructBE.fromModelTypes(iotModel, types);
const senderData = {
  iotName: 'IOT-1',
  sensor: {
    id: 123456789,
    type: 0x01,
    value: 123.456,
    timestamp: 1677277903685n,
  }
};
const { buffer: senderFrame } = sender.make(senderData);

// Transmitting frame
console.log(senderFrame.toString('hex'));

// IOT Receiver
const receiver = CStructBE.fromModelTypes(iotModel, types);
const { struct: receiverData } = receiver.read(senderFrame);
console.log(receiverData);
// {
//   iotName: 'IOT-1',
//   sensor: {
//      id: 123456789,
//      type: 1,
//      value: 123.456,
//      timestamp: 1677277903685
//    }
//  }

String based examples. Model and Types are strings but you can mix approach

import { CStructBE } from '@mrhiden/cstruct';

// Make buffer from struct based on model and types
const cStruct = CStructBE.fromModelTypes(`{errors: [Error, Error]}`, `{Error: {code: u16, message: s10}}`);

const {buffer, offset, size} = cStruct.make({
    errors: [
        {code: 0x12, message: 'message1'},
        {code: 0x34, message: 'message2'},
    ]
});

console.log(buffer.toString('hex'));
// 00126d65737361676531000000346d657373616765320000
console.log(offset);
// 24
console.log(size);
// 24
import { CStructBE } from '@mrhiden/cstruct';

// Mixed approach for model and types
const cStruct = CStructBE.fromModelTypes({errors: `[Error, Error]`}, {Error: `{code: u16, message: s10}`});

const {buffer, offset, size} = cStruct.make({
    errors: [
        {code: 0x12, message: 'message1'},
        {code: 0x34, message: 'message2'},
    ]
});

console.log(buffer.toString('hex'));
// 00126d65737361676531000000346d657373616765320000
console.log(offset);
// 24
console.log(size);
// 24

C-kind data fields

import { CStructBE } from '@mrhiden/cstruct';

// C-kind fields {u8 a,b;} into {a:u8,b:u8}
const model = `{u8 a,b;}`;
const cStruct = CStructBE.fromModelTypes(model);

const makeStruct = { a: 1, b: 2 };
const { buffer: structBuffer } = cStruct.make(
    makeStruct
);
console.log(structBuffer.toString('hex'));
// 0102

const { struct: readStruct } = cStruct.read(structBuffer);
console.log(readStruct);
// { a: 1, b: 2 }

Dynamic length

import { CStructBE } from '@mrhiden/cstruct';

// Dynamic (length) array with types
const model = {
    ab: "Ab[i16]",
};

const types = {
    Ab: {a: 'i8', b: 'i8'}
};

const cStruct = CStructBE.fromModelTypes(model, types);

console.log(cStruct.modelClone);
// { 'ab.i16': { a: 'i8', b: 'i8' } }

const data = {
    ab: [
        {a: '-1', b: '+1'},
        {a: '-2', b: '+2'},
    ]
};
const {buffer} = cStruct.make(data);

console.log(buffer.toString('hex'));
// 0002ff01fe02

const {struct: extractedData} = cStruct.read(buffer);
console.log(extractedData);
// { ab: [ { a: -1, b: 1 }, { a: -2, b: 2 } ] }
import { CStructBE } from '@mrhiden/cstruct';

// Dynamic (length) string
const model = {
    txt1: "s[i16]",
    txt2: "string[i16]",
};

const cStruct = CStructBE.fromModelTypes(model);

console.log(cStruct.modelClone);
// { 'txt1.i16': 's', 'txt2.i16': 's' }

const data = {
    txt1: "ABCDE",
    txt2: "AB"
};
const {buffer} = cStruct.make(data);

console.log(buffer.toString('hex'));
// 0005414243444500024142
// 0005_4142434445 0002_4142

const {struct: extractedData} = cStruct.read(buffer);
console.log(extractedData);
// { txt1: 'ABCDE', txt2: 'AB' }

PLC example

import { CStructBE } from '@mrhiden/cstruct';

const model = {b: 'BYTE', w: 'WORD', f: 'BOOL'};

const cStruct = CStructBE.fromModelTypes(model);

console.log(cStruct.modelClone);
// { b: 'BYTE', w: 'WORD', f: 'BOOL' }

const struct = {b: 0x12, w: 0x3456, f: true};
const {buffer} = cStruct.make(struct);

console.log(buffer.toString('hex'));
// 12345601
// 12 3456 01

const {struct: extractedData} = cStruct.read(buffer);
console.log(extractedData);
// { b: 18, w: 13398, f: true }
// { b: 0x12, w: 0x3456, f: true }

C-kind struct

import { CStructBE } from '@mrhiden/cstruct';

// C struct types
const model = {
    xyzs: "Xyx[2]",
};
const types = `{
    typedef struct {
        uint8_t x;
        uint8_t y;
        uint8_t z;
    } Xyx;
}`;

const cStruct = CStructBE.fromModelTypes(model, types);

const data = {
    xyzs: [
        {x: 1, y: 2, z: 3},
        {x: 4, y: 5, z: 6},
    ]
};
const {buffer: makeBuffer} = cStruct.make(data);

console.log(makeBuffer.toString('hex'));
// 010203040506

const {struct: readStruct} = cStruct.read(makeBuffer);
console.log(readStruct);
// { xyzs: [ { x: 1, y: 2, z: 3 }, { x: 4, y: 5, z: 6 } ] }
import { CStructBE } from '@mrhiden/cstruct';

// C struct types
const types = `{
    // 1st approach
    typedef struct {
        u8 x,y,z;
    } Xyz;
    
    // 2nd approach
    struct Ab {
        i8 x,y;
    };
    
    // As you noticed, comments are allowed
}`;
const model = `{
    ab: Ab,
    xyz: Xyz,
    
    // As you noticed, comments are allowed
}`;

const cStruct = CStructBE.fromModelTypes(model, types);

const data = {
    ab: { x: -2, y: -1 },
    xyz: { x: 0, y: 1, z: 2 }
};
const {buffer: makeBuffer} = cStruct.make(data);

console.log(makeBuffer.toString('hex'));
// feff000102

const {struct: readStruct} = cStruct.read(makeBuffer);
console.log(readStruct);
// { ab: { x: -2, y: -1 }, xyz: { x: 0, y: 1, z: 2 } }
import { CStructBE } from '@mrhiden/cstruct';

// Value, static array, dynamic array
const model = `[
    i8,         // 1 byte
    i8[2],      // 2 bytes static array
    i8[i16]     // i16 bytes dynamic array
]`;

const cStruct = CStructBE.fromModelTypes(model);

console.log(cStruct.jsonModel);
// ["i8","i8.2","i8.i16"]
console.log(cStruct.modelClone);
// [ 'i8', 'i8.2', 'i8.i16' ]

const data = [
    0x01,
    [0x02, 0x03],
    [0x04, 0x05, 0x06, 0x07],
];
const {buffer} = cStruct.make(data);

console.log(buffer.toString('hex'));
// 010203000404050607
// 01 02_03 0004_04_05_06_07

const {struct: extractedData} = cStruct.read(buffer);
console.log(extractedData);
// [ 1, [ 2, 3 ], [ 4, 5, 6, 7 ] ]
import { CStructBE } from '@mrhiden/cstruct';

class Undecorated {
    a: number;
    b: number;
}
const undecorated = new Undecorated();
undecorated.a = -1;
undecorated.b = -2;

const undecoratedStruct = CStructBE.from({
    model: '{a:float,b:double}',
});
const undecoratedBuffer = undecoratedStruct.make(undecorated).buffer;
console.log(undecoratedBuffer.toString('hex'));
// bf800000c000000000000000
// bf800000 c000000000000000

Decorators

TypeScript's decorators to serialize/deserialize class object to/from binary

NOTE Take a look on '/examples/decorators.ts'

MUST enable in tsconfig.json or jsconfig.json

{
  "compilerOptions": {
    "experimentalDecorators": true
  }
}
import { CStructBE, CStructClass, CStructModelProperty } from '@mrhiden/cstruct';

// Decorators - Serialize any class with CStructClass and CStructModelProperty decorator, model and type
class MyClass {
    public a: number;
    public b: number;
}

@CStructClass({
    types: {MyClass: {a: 'u16', b: 'i16'}}
})
class MyData {
    @CStructModelProperty('MyClass')
    public myClass: MyClass;
}

const myData = new MyData();
myData.myClass = new MyClass();
myData.myClass.a = 10;
myData.myClass.b = -10;

// MAKE
const bufferMake = CStructBE.make(myData).buffer;
console.log(bufferMake.toString('hex'));
// 000afff6
// 000a fff6

// READ
const myDataRead = new MyData();
myDataRead.myClass = new MyClass();
CStructBE.read(myDataRead, bufferMake);
console.log(myDataRead);
// MyData { myClass: MyClass { a: 10, b: -10 } }

// WRITE
const bufferWrite = Buffer.alloc(4);
CStructBE.write(myData, bufferWrite);
console.log(bufferWrite.toString('hex'));
// 000afff6
// 000a fff6

Some more realistic example

import { CStructBE } from '@mrhiden/cstruct';
import * as fs from "fs";

interface GeoAltitude {
    lat: number;
    long: number;
    alt: number;
}

@CStructClass({
    types: `{ GeoAltitude: { lat:double, long:double, alt:double }}`
})
class GeoAltitudesFile {
    @CStructProperty({type: 'string30'})
    public fileName: string = 'GeoAltitudesFile v1.0';

    @CStructProperty({type: 'GeoAltitude[i32]'})
    public geoAltitudes: GeoAltitude[] = [];
}

(async () => {
    // Make random data
    const geoAltitudesFile = new GeoAltitudesFile();
    for (let i = 0; i < 1e6; i++) {
        let randomLat = Math.random() * (90 - -90) + -90;
        let randomLong = Math.random() * (180 - -180) + -180;
        let randomAlt = 6.4e6 * Math.random() * (8e3 - -4e3) + -4e3;
        const geo = {lat: randomLat, long: randomLong, alt: randomAlt};
        geoAltitudesFile.geoAltitudes.push(geo);
    }
    console.log('Write data length,', geoAltitudesFile.geoAltitudes.length);

    // Make buffer
    console.time('make');
    const writeFile = CStructBE.make(geoAltitudesFile).buffer;
    console.timeEnd('make');
    
    // Write to file
    console.log('Write file length,', writeFile.length);
    await fs.promises.writeFile('geoAltitudesFile.bin', writeFile);

    // Read from file
    const readFile = await fs.promises.readFile('geoAltitudesFile.bin');
    console.log('Read file length,', readFile.length);

    // Read data
    console.time('read');
    const readGeoAltitudesFile = CStructBE.read(GeoAltitudesFile, readFile).struct;
    console.timeEnd('read');

    console.log('Read fileName,', readGeoAltitudesFile.fileName);
    console.log('Read data length,', readGeoAltitudesFile.geoAltitudes.length);
})();

JSON mode

import { CStructBE } from '@mrhiden/cstruct';

@CStructClass({
    model: {
        any1: 'j[i8]',
        any2: 'json[i8]',
        any3: 'any[i8]',
    }
})
class MyClass {
    any1: any;
    any2: any;
    any3: any;
}

const myClass = new MyClass();
myClass.any1 = {a: 1};
myClass.any2 = {b: "B"};
myClass.any3 = [1, 3, 5];

const buffer = CStructBE.make(myClass).buffer;
console.log(buffer.toString('hex'));
// 077b2261223a317d097b2262223a2242227d075b312c332c355d
// 07_7b2261223a317d 09_7b2262223a2242227d 07_5b312c332c355d
const myClass2 = CStructBE.read(MyClass, buffer).struct;
console.log(myClass2);
// MyClass {
//   any1: { a: 1 },
//   any2: { b: 'B' },
//   any3: [ 1, 3, 5 ]
// }

Trailing zero support for "string", "wstring" and "json" types ("s", "string", "ws", "wstring", "j", "json", "any")

This library has support for trailing zero for "string" and "json" types. When you use it "json" and "string" will be written as full unknown length and '\0' will be added at the end. That ending zero helps to read data from binary file without knowing the length of the string / json. We can not use that trick with buffer as it may contain zeros at any place. For wstring/utf16le trailing character is/must be 16bit zero '\u0000'.

import { CStructBE } from '@mrhiden/cstruct';

const model = {
    any1: 'j[0]', // or 'json[0]' or 'any[0]'
    any2: 's[0]', // or 'string[0]'
};

const cStruct = CStructBE.fromModelTypes(model);

const data = {
    any1: [1, 2, 3],
    any2: 'abc',
};

const buffer = cStruct.make(data).buffer;
console.log(buffer.toString('hex'));
// 5b312c322c335d0061626300
// 5b_31_2c_32_2c_33_5d_00 616263_00
// [  1  ,  2  ,  3  ]  \0 a b c  \0

const extractedData = cStruct.read(buffer).struct;
console.log(extractedData);
// { any1: [ 1, 2, 3 ], any2: 'abc' }

console.log(JSON.stringify(data) === JSON.stringify(extractedData));
// true

TODO

Contact

If you have any questions or suggestions, please contact me at [email protected]