js-c-struct
v1.0.0
Published
Replicates C Struct for JavaScript
Downloads
1
Readme
- Basic installation and usage
- Class: Struct
- Types
- Byte swapping
- Recursive Structures (experimental)
- LICENSE
Basic installation
You can install this package either by using npm or by downloading the source from GitHub and requiring it directly.
To install using npm open your terminal (or command line), make sure you're in your application directory and execute the following command:
npm install js-c-struct
You can then start using the package by requiring it from your application as such:
const { Struct } = require('js-c-struct');
⚠️ There is no error handler for now, use this package carefully ⚠️
Class: Struct
new Struct(...definitions[, name])
...definitions
:<Proxy<T>[]>
The definitions of the structure. See Types for more informationname
:<String>
The name of the structure.- Returns :
<Struct>
Create a new structure.
const { Struct, types: { int, byte } } = require('js-c-struct');
let Hashize = new Struct(
int.size,
byte.crc32[4]
, "Hashize");
static
read(struct, buffer)
struct
:<Struct>
The structure you want to affect the bufferbuffer
:<TypedArray>
|<Buffer>
The buffer you want to affect- Returns :
<Struct>
Read the buffer with the definitions gave in the constructor and make a new readed structure of it.
let buffer = new Uint8Array([0x9a, 0x02, 0x00, 0x00, 0x3a, 0x45, 0xf4, 0xc5]);
let hashize = Struct.read(Hashize, buffer);
static
json(struct)
struct
:<Struct>
The structure you want to extract the JSON- Returns :
<Class>
Extract the data of the structure into a json.
⚠️ Can only be done after reading the structure
The returned object is a class because of the name you can give to the structure, but it doesn't change anything. 😉
console.log( Struct.json(hashize) );
// Hashize {
// size: 666,
// crc32: Uint8Array(4) [ 58, 69, 244, 197 ]
// }
static
buffer(struct)
struct
:<Struct>
The structure you want to extract the Buffer- Returns :
<Uint8Array>
Extract the data of the structure into an Uint8Array.
⚠️ Can only be done after reading the structure
Can be nice if you want to modify some values in the structure and get the buffer back.
(⚠️ Editing structures can only be done on non recursive one)
hashize.size = 42;
console.log( Struct.buffer(hashize) );
// Uint8Array(8) [42, 0, 0, 0, 58, 69, 244, 197]
static
sizeof(struct)
struct
:<Struct>
The structure you want the size- Returns :
<Number>
Return the size of the structure.
⚠️ On recursive struct this function can only be done after reading the structure
console.log( Struct.sizeof(Hashize) ); // it work too with hashize
// 8
static
isInitialized(struct)
struct
:<Struct>
The structure you want to see the state- Returns :
<boolean>
Know if the structure is readed or not
console.log( Struct.isInitialized(hashize) ) // true
console.log( Struct.isInitialized(Hashize) ) // false
static
isRecursive(struct)
struct
:<Struct>
The structure you want to see if it is a Recursive Structure- Returns :
<boolean>
Know if the structure is recursive or not
console.log( Struct.isRecursive(Hashize) ) // false
// false
let Name = new Struct(
int.length,
int.name["length"]
);
console.log( Struct.isRecursive(Name) ) // true
static
isStruct(struct)
struct
:<Struct>
The structure you want to test- Returns :
<boolean>
Returns true
if struct
is a Struct
, false
otherwise.
let struct = new Struct( /* ... */ );
let uint8array = new Uint8Array();
console.log( Struct.isStruct(struct) );
// true
console.log( Struct.isStruct(uint8array) );
// false
Types
To understand types we need first to understand how struct is formed in c:
struct Person {
int age;
char name[16];
struct Family family; // a structure Family need to be defined before
}
// The next is optional, it is only used to declare a new type in C, but in JS we don't need that, but imagine that we can make it by naming our Struct
typedef Person person_t
With that example, you understand what is ...definitions
in the Struct constructor
To create c like definitions like this in javascript, i use Proxy, so int age
become int.age
and char name[16]
become char.name[16]
So now you're surely asking, how struct definitions are made ?
To do struct definition, you need to use the Struct class but not creating a new one with new
expression, just creating it like a normal function. So struct Family family
become Struct(Family).family
The above example in c, will look like this
let Person = new Struct(
int.age,
char.name[16],
Struct(Family).family // Same as C, a structure Family need to be defined before
, "person_t") // Structure name is optional, it is used for JSON logging, to know what struct correspond an object
To import above types you need to do
let { Struct, types: { int, char } } = require("js-c-struct");
Default types arechar
, bool
, int8
, uint8
, byte
, sbyte
, int16
,uint16
, int32
, uint32
, int64
, uint64
, float
and double
(⚠️ byte
is uint8 and sbyte
is int8, int64
and uint64
are BigInt values)
Generic C types are also present but declined by data models.
There is 5 data models: C Standard
, LP32
, ILP32
, LLP64
and LP64
See more info here.
To import these special type replace types
above with standard
, lp32
, ilp32
, llp64
or lp64
. Keep in mind that all default types are present in each models and that types
import is the same as ilp32
These models import short
, int
, long
and long long
(that can be done via long.long
)
There are too, two special type: signed
and unsigned
.
These special types accept 6 types: char
, byte
, short
, int
, long
and long long
.
So if you want to create a uint32 with ILP32 model, you need to do:
const { ilp32: { unsigned } } = require("js-c-struct");
unsigned.int.definition;
// You can also do
const { ilp32: { unsigned: { int } } } = require("js-c-struct");
int.definition;
Or a uint64 with LLP64 ?
const { llp64: { unsigned } } = require("js-c-struct");
unsigned.long.long.definition;
Note that all types can be imported with _t
at the end (for faster c to js conversion)
Byte swapping
Swapping byte is made after reading the struct in C by doing bswap16
, bswap32
or bswap64
functions, these functions can be imported in js-struct like this:
const { bswap16, bswap32, bswap64 } = require("js-c-struct");
But it is boring to do a new variable for swapping the bytes from little to big right ?
This is why by adding ...
before your definition, it will make it big endian in the structure.
Example:
let LittleBigEndian = new Struct(
int.little,
...int.big
);
Recursive Structure (experimental)
⚠️ Recursive structures are read-only because their size is unpredictable and modify certain values need to modify another one, there will surely be a system later to make writing possible.
Recursive structure are structure that read the length value directly with a previous readed one.
For example if i have created a definition called nameLen
in the structure before, i need to do char.name["nameLen"]
to get the right char array of the name.
Imagine now that we have a partition with block_size of 4096 bits, and that we have a file with a block_length of X blocks in the partition. The solution is simple, you can do byte.file["=$block_length*$block_size"]
or byte.file["=$block_length*4096"]
if block_size is not defined and already known.