Package Exports
- node-structor
- node-structor/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (node-structor) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
node-structor
Convert binary file data to JavaScript objects
Installation
npm i node-structor
Usage
In the example below we will be reading a list of people from a binary source.
const fs = require('fs')
const Structor = require('node-structor')
const structDef = {
numPersons: {
$format: 'byte',
$ignore: true
},
persons: {
$repeat: 'numPersons',
$format: {
firstName: 'string7',
lastName: 'string7',
address: {
city: 'string7',
street: 'string7',
number: 'uint16',
zipCode: 'string7'
},
numHobbies: {
$ignore: true,
$format: 'byte'
},
hobbies: {
$format: 'string7',
$repeat: 'numHobbies'
}
}
}
}
let result = Structor.readStruct(structDef, fs.readFileSync('./examples/people.dat'))
console.log(result)Note that
'string7'is used - this denotes a string that is prepended by the length of that string. Reference.
Running this will log the following:
{
persons: [
{
firstName: 'John',
lastName: 'A',
address: {
city: 'New York',
street: '1st Ave.',
number: 1165,
zipCode: '10065'
},
hobbies: ['eating', 'coding', 'walking']
},
{
firstName: 'Betty',
lastName: 'B',
address: {
city: 'York',
street: 'Bridge St.',
number: 1,
zipCode: 'YO1 6DD'
},
hobbies: []
}
]
}API
readStruct(structDef, buffer, [options])
Reads the binary data from the buffer according to the structure definition. Returns a JavaScript object.
writeStruct(obj, structDef, data, [options])
Writes the an object to a binary buffer according to the structure definition. Returns the number of bytes written.
sizeOf(structDef, [size = 4096])
Calculates the size of the binary data that would be written according to the structure definition. The size parameter is optional and defaults to 4096; it references the size of the buffer that will be allocated to be able to calculate the size of the data.
Types
| Type | Description |
|---|---|
byte |
Unsigned byte (0 to 255) |
uint8 |
Unsigned byte (0 to 255) |
sbyte |
Signed byte (-128 to 127) |
int8 |
Signed byte (-128 to 127) |
uint16 |
16-bit unsigned integer (0 to 65,535) |
int16 |
16-bit signed integer (-32,768 to 32,767) |
uint32 |
32-bit unsigned integer (0 to 4,294,967,295) |
int32 |
32-bit signed integer (-2,147,483,648 to 2,147,483,647) |
uint64 |
64-bit unsigned integer (read as BigInt) |
int64 |
64-bit signed integer (read as BigInt) |
char_* |
A string of characters with its length defined by the *. e.g. char_28 |
string0 |
A string of characters terminated by a zero (0) byte. When used with writeStruct, it will write the string with a zero byte at the end. |
string7 |
A string of characters prepended by its 7-bit encoded length |
string |
Can only be used in conjunction with $format. Read $length amount of bytes as a new string. Can also be used with $encoding to specify the encoding. Default is utf8. |
buffer |
Can only be used in conjunction with $format. Read $length amount of bytes as a new Buffer. |
Note: By default the endianness is little-endian (LE) - But you can explicitly define the endianness e.g.
int16be,uint64le, etc.
Directives
$format
Define the format. This can be any of the types mentioned above, or another structure definition.
Examples:
{
someNumber: {
$format: 'uint16' // Results in a single number
},
anotherNumber: 'uint16' // Short-hand for the above
}Some types only work in conjunction with $format, as they require extra information to be on the same level. These are: string and buffer.
Examples:
{
name: {
$format: 'string',
$length: 32,
$encoding: 'ascii' // $encoding is optional, default is 'utf8'
}
}{
blobData: {
$format: 'buffer',
$length: 64000
}
}$repeat
Repeats the specified $format. Can be a number or the name of a property containing the value.
Examples:
{
$format: 'byte',
$repeat: 2
}{
numObjects: 'byte',
objects: {
$format: {
...
},
$repeat: 'numObjects'
}
}$foreach
A special form of $repeat. Must be a referenced value pointing to a previously read array combined with an alias.
Examples:
{
numFiles: 'uint16',
fileTable: {
$repeat: 'numFiles',
$format: {
name: 'char_24',
address: 'uint32',
length: 'uint32'
}
},
files: {
// Iterate over each item in fileTable as 'file'
$foreach: 'fileTable file',
$format: {
fileName: {
$value: 'file.name',
$format: 'char_24'
},
fileContent: {
$goto: 'file.address',
$format: 'buffer',
$length: 'file.length'
}
}
}
}$switch
Read the next data differently based on a previously read value. A default case can optionally be defined.
Examples:
const struct = {
type: 'byte',
shape: {
$switch: 'type',
$cases: {
1: { // when type is 1, assume circle data follows
$format: {
radius: 'uint32'
}
},
2: { // when type is 2, assume rectangle data follows
$format: {
width: 'uint16',
height: 'uint16'
}
},
3: { // when type is 3, assume polygon data follows
$format: {
numPoints: 'byte',
points: {
$repeat: 'numPoints',
$format: {
x: 'byte',
y: 'byte'
}
}
}
},
default: {
$format: {
unknown: 'byte'
}
}
}
}
}
// Which could result in:
{
type: 1,
shape: {
radius: 38892
}
}
// or:
{
type: 2,
shape: {
width: 96,
height: 128
}
}
// or:
{
type: 3,
shape: {
points: [
{ x: 0, y: 2 },
{ x: 128, y: 24 },
{ x: 255, y: 8 }
]
}
}
$ignore
Read the data, but don't put the property in the eventual JS object. Its value can still be used as a referenced value in other directives.
Examples:
numObjects: {
$format: 'byte',
$ignore: true
}$goto
Jumps to the specified byte location before reading the value.
Examples:
signature: {
$goto: 0xf0,
$format: 'char_2'
}$skip
Skips the specified number of bytes before reading the value.
Examples:
startOfHeader: {
$skip: 255,
$format: 'uint16'
}$length
Can be used in conjunction with $format: 'string' and must be used when $format: 'buffer'.
Examples:
firstName: {
$format: 'string',
$length: 32
}Note: when
$formatis'string',$lengthis optional. If not present, characters will be read until a zero-byte is encountered.
blobData: {
$format: 'buffer',
$length: 64000
}$encoding
Can only be used in conjunction with $format: 'string'.
Examples:
firstName: {
$format: 'string',
$encoding: 'ascii'
}Note: the default value for
$encodingis'utf8'
$value
A special directive that doesn't read anything from the buffer and thus doesn't move the internal cursor. Used to copy a value from another source.
{
name: 'string',
nameCopy: {
$value: 'name',
$format: 'uint32'
}
}$tell
A special directive that reads the current position of the internal cursor. Must be used in conjunction with $format: '$tell'.
{
name: 'string',
currentAddress: {
$format: '$tell',
$tell: 'uint16'
}
}Referenced values
Every numeric directive supports passing a reference value string instead of a hard-coded integer. This can be a simple name pointing to a sibling value, or a more complex path.
Examples:
{
nameLength: 'byte',
myName: {
$format: 'string',
$length: 'nameLength'
}
}{
header: {
config: {
nameLength: 'byte'
}
},
myName: {
$format: 'string',
$length: 'header.config.nameLength'
}
}Directives that support this:
$repeat$switch$length(see above examples)$goto$skip$value