Skip to content

Commit 0287201

Browse files
committed
Merge PR #18 from
2 parents 3819684 + a3a6cf8 commit 0287201

29 files changed

+4128
-3481
lines changed

.circleci/config.yml

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,70 @@
11
version: 2
2+
3+
defaults: &defaults
4+
working_directory: ~/repo
5+
docker:
6+
- image: circleci/node
7+
28
jobs:
39
build:
4-
docker:
5-
- image: circleci/node
10+
<<: *defaults
611
steps:
712
- checkout
813
- restore_cache:
914
key: deps-{{ checksum "package-lock.json" }}
1015
- run:
1116
command: npm install
1217
- run:
13-
command: npm test
14-
- run:
15-
command: npm run check-fmt
18+
command: npm install --no-save mocha-junit-reporter
1619
- save_cache:
1720
key: deps-{{ checksum "package-lock.json" }}
1821
paths:
1922
- node_modules/
23+
- persist_to_workspace:
24+
root: ~/repo
25+
paths: .
26+
test:
27+
<<: *defaults
28+
steps:
29+
- attach_workspace:
30+
at: ~/repo
31+
- run:
32+
command: npx mocha --reporter mocha-junit-reporter
33+
environment:
34+
MOCHA_FILE: test-results/mocha/results.xml
35+
- store_test_results:
36+
path: test-results
37+
- run:
38+
command: npm run check-fmt
39+
publish:
40+
<<: *defaults
41+
steps:
42+
- attach_workspace:
43+
at: ~/repo
44+
- run:
45+
command: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc
46+
- run:
47+
command: npm publish
48+
49+
workflows:
50+
version: 2
51+
build-test-publish:
52+
jobs:
53+
- build:
54+
filters:
55+
tags:
56+
only: /^v.*/
57+
- test:
58+
requires:
59+
- build
60+
filters:
61+
tags:
62+
only: /^v.*/
63+
- publish:
64+
requires:
65+
- test
66+
filters:
67+
tags:
68+
only: /^v.*/
69+
branches:
70+
ignore: /.*/

.editorconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
root = true
2+
3+
[*]
4+
end_of_line = lf
5+
charset = utf-8
6+
trim_trailing_whitespace = true
7+
insert_final_newline = true
8+
9+
[*.{ts,js,json}]
10+
indent_style = space
11+
indent_size = 2

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,6 @@ node_modules
1717

1818
coverage/
1919
.nyc_output/
20+
dist/
21+
22+
.cache/

.npmignore

Lines changed: 0 additions & 3 deletions
This file was deleted.

.prettierrc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"parser": "typescript",
3+
"trailingComma": "es5",
4+
"tabWidth": 2,
5+
"semi": true,
6+
"singleQuote": true
7+
}

LICENSE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright (c) 2013-2017 Keichi Takahashi <keichi.t@me.com>
1+
Copyright (c) 2013-2019 Keichi Takahashi <keichi.t@me.com>
22

33
Permission is hereby granted, free of charge, to any person obtaining a copy
44
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 96 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -17,31 +17,29 @@ data. Binary-parser dynamically generates and compiles the parser and encoder co
1717
on-the-fly, which runs as fast as a hand-written parser/encoder (which takes much more
1818
time and effort to write). Supported data types are:
1919

20-
- Integers (supports 8, 16, 32 bit signed- and unsigned integers)
21-
- Floating point numbers (supports 32 and 64 bit floating point values)
22-
- Bit fields (supports bit fields with length from 1 to 32 bits)
23-
- Strings (supports various encodings, fixed-length and variable-length, zero
24-
terminated string)
25-
- Arrays (supports user-defined element type, fixed-length and variable-length)
26-
- Choices
27-
- User defined types
28-
29-
This library's features are inspired by [BinData](https://github.com/dmendel/bindata)
30-
, its syntax by [binary](https://github.com/substack/node-binary).
31-
32-
## Installation
33-
Binary-parser can be installed with [npm](https://npmjs.org/):
34-
35-
```shell
36-
$ npm install binary-parser
37-
```
20+
- [Integers](#uint8-16-32-64le-bename-options) (8, 16, 32 and 64 bit signed
21+
and unsigned integers)
22+
- [Floating point numbers](#float-doublele-bename-options) (32 and 64 bit
23+
floating point values)
24+
- [Bit fields](#bit1-32name-options) (bit fields with length from 1 to 32
25+
bits)
26+
- [Strings](#stringname-options) (fixed-length, variable-length and zero
27+
terminated strings with various encodings)
28+
- [Arrays](#arrayname-options) (fixed-length and variable-length arrays of
29+
builtin or user-defined element types)
30+
- [Choices](#choicename-options) (supports integer keys)
31+
- [Pointers](#pointername-options)
32+
- User defined types (arbitrary combination of builtin types)
33+
34+
Binary-parser was inspired by [BinData](https://github.com/dmendel/bindata)
35+
and [binary](https://github.com/substack/node-binary).
3836

3937
## Quick Start
40-
1. Create an empty Parser object with `new Parser()`.
41-
2. Chain builder methods to build the desired parser and/or encoder. (See
42-
[API](https://github.com/Keichi/binary-parser#api) for detailed document of
43-
each methods)
44-
3. Call `Parser.prototype.parse` with an `Buffer` object passed as argument.
38+
1. Create an empty Parser object with `new Parser()` or `Parser.start()`.
39+
2. Chain methods to build your desired parser and/or encoder. (See
40+
[API](https://github.com/keichi/binary-parser#api) for detailed document of
41+
each method)
42+
3. Call `Parser.prototype.parse` with an `Buffer` object passed as an argument.
4543
4. Parsed result will be returned as an object.
4644
5. Or call `Parser.prototype.encode` with an object passed as argument.
4745
6. Encoded result will be returned as a `Buffer` object.
@@ -106,8 +104,8 @@ parser.
106104

107105
### parse(buffer)
108106
Parse a `Buffer` object `buffer` with this parser and return the resulting
109-
object. When `parse(buffer)` is called for the first time, parser code is
110-
compiled on-the-fly and internally cached.
107+
object. When `parse(buffer)` is called for the first time, the associated
108+
parser code is compiled on-the-fly and internally cached.
111109

112110
### encode(obj)
113111
Encode an `Object` object `obj` with this parser and return the resulting
@@ -118,12 +116,17 @@ compiled on-the-fly and internally cached.
118116
Set the constructor function that should be called to create the object
119117
returned from the `parse` method.
120118

121-
### [u]int{8, 16, 32}{le, be}(name[, options])
119+
### [u]int{8, 16, 32, 64}{le, be}(name[, options])
122120
Parse bytes as an integer and store it in a variable named `name`. `name`
123121
should consist only of alphanumeric characters and start with an alphabet.
124-
Number of bits can be chosen from 8, 16 and 32. Byte-ordering can be either
122+
Number of bits can be chosen from 8, 16, 32 and 64. Byte-ordering can be either
125123
`l` for little endian or `b` for big endian. With no prefix, it parses as a
126-
signed number, with `u` prefixed as an unsigned number.
124+
signed number, with `u` prefixed as an unsigned number. The runtime type
125+
returned by the 8, 16, 32 bit methods is `number` while the type
126+
returned by the 64 bit is `bigint`.
127+
128+
**Note:** [u]int64{be,le} methods only work if your runtime is node v12.0.0 or
129+
greater. Lower version will throw a runtime error.
127130

128131
```javascript
129132
var parser = new Parser()
@@ -133,6 +136,8 @@ var parser = new Parser()
133136
.uint8("b")
134137
// Signed 16-bit integer (big endian)
135138
.int16be("c");
139+
// signed 64-bit integer (big endian)
140+
.int64be("d")
136141
```
137142

138143
### bit\[1-32\](name[, options])
@@ -141,9 +146,8 @@ methods from `bit1` to `bit32` each corresponding to 1-bit-length to
141146
32-bits-length bit field.
142147

143148
### {float, double}{le, be}(name[, options])
144-
Parse bytes as an floating-point value and store it in a variable named
145-
`name`. `name` should consist only of alphanumeric characters and start with
146-
an alphabet.
149+
Parse bytes as a floating-point value and stores it to a variable named
150+
`name`.
147151

148152
```javascript
149153
var parser = new Parser()
@@ -159,7 +163,7 @@ characters and start with an alphabet. `options` is an object which can have
159163
the following keys:
160164

161165
- `encoding` - (Optional, defaults to `utf8`) Specify which encoding to use.
162-
`"utf8"`, `"ascii"`, `"hex"` and else are valid. See
166+
Supported encodings include `"utf8"`, `"ascii"` and `"hex"`. See
163167
[`Buffer.toString`](http://nodejs.org/api/buffer.html#buffer_buf_tostring_encoding_start_end)
164168
for more info.
165169
- `length ` - (Optional) (Bytes)Length of the string. Can be a number, string or a
@@ -190,15 +194,17 @@ the following keys:
190194
- `clone` - (Optional, defaults to `false`) By default,
191195
`buffer(name [,options])` returns a new buffer which references the same
192196
memory as the parser input, but offset and cropped by a certain range. If
193-
this option is true, input buffer will be cloned and a new buffer referncing
194-
another memory is returned.
197+
this option is true, input buffer will be cloned and a new buffer
198+
referencing a new memory region is returned.
195199
- `length ` - (either `length` or `readUntil` is required) Length of the
196200
buffer. Can be a number, string or a function. Use number for statically
197201
sized buffers, string to reference another variable and function to do some
198202
calculation.
199203
- `readUntil` - (either `length` or `readUntil` is required) If `"eof"`, then
200204
this parser will read till it reaches end of the `Buffer` object. (Note: has no
201205
effect on encoding.)
206+
If it is a function, this parser will read the buffer is read until the
207+
function returns true.
202208

203209
### array(name, options)
204210
Parse bytes as an array. `options` is an object which can have the following
@@ -242,7 +248,7 @@ var parser = new Parser()
242248
type: "int32",
243249
length: function() {
244250
return this.dataLength - 1;
245-
} // other fields are available through this
251+
} // other fields are available through `this`
246252
})
247253

248254
// Statically sized array
@@ -263,7 +269,7 @@ var parser = new Parser()
263269
type: "int32",
264270
lengthInBytes: function() {
265271
return this.dataLengthInBytes - 4;
266-
} // other fields are available through this
272+
} // other fields are available through `this`
267273
})
268274

269275
// Dynamically sized array (with stop-check on parsed item)
@@ -291,7 +297,7 @@ an object which can have the following keys:
291297
`choices` Can be a string pointing to another field or a function.
292298
- `choices` - (Required) An object which key is an integer and value is the
293299
parser which is executed when `tag` equals the key value.
294-
- `defaultChoice` - (Optional) In case of the tag value doesn't match any of
300+
- `defaultChoice` - (Optional) In case if the tag value doesn't match any of
295301
`choices`, this parser is used.
296302

297303
```javascript
@@ -302,15 +308,15 @@ var parser3 = ...;
302308
var parser = new Parser().uint8("tagValue").choice("data", {
303309
tag: "tagValue",
304310
choices: {
305-
1: parser1, // When tagValue == 1, execute parser1
306-
4: parser2, // When tagValue == 4, execute parser2
307-
5: parser3 // When tagValue == 5, execute parser3
311+
1: parser1, // if tagValue == 1, execute parser1
312+
4: parser2, // if tagValue == 4, execute parser2
313+
5: parser3 // if tagValue == 5, execute parser3
308314
}
309315
});
310316
```
311317

312318
Combining `choice` with `array` is an idiom to parse
313-
[TLV](http://en.wikipedia.org/wiki/Type-length-value)-based formats.
319+
[TLV](http://en.wikipedia.org/wiki/Type-length-value)-based binary formats.
314320

315321
### nest([name,] options)
316322
Execute an inner parser and store its result to key `name`. If `name` is null
@@ -319,9 +325,46 @@ current object. `options` is an object which can have the following keys:
319325

320326
- `type` - (Required) A `Parser` object.
321327

322-
### skip(length)
323-
Skip parsing for `length` bytes. (Note: when encoding, the skipped bytes will be filled
324-
with zeros)
328+
### pointer(name [,options])
329+
Jump to `offset`, execute parser for `type` and rewind to previous offset.
330+
Useful for parsing binary formats such as ELF where the offset of a field is
331+
pointed by another field.
332+
333+
- `type` - (Required) Can be a string `[u]int{8, 16, 32, 64}{le, be}`
334+
or an user defined Parser object.
335+
- `offset` - (Required) Indicates absolute offset from the beginning of the
336+
input buffer. Can be a number, string or a function.
337+
338+
### saveOffset(name [,options])
339+
Save the current buffer offset as key `name`. This function is only useful
340+
when called after another function which would advance the internal buffer
341+
offset.
342+
343+
```javascript
344+
var parser = new Parser()
345+
// this call advances the buffer offset by
346+
// a variable (i.e. unknown to us) number of bytes
347+
.string('name', {
348+
zeroTerminated: true
349+
})
350+
// this variable points to an absolute position
351+
// in the buffer
352+
.uint32('seekOffset')
353+
// now, save the "current" offset in the stream
354+
// as the variable "currentOffset"
355+
.saveOffset('currentOffset')
356+
// finally, use the saved offset to figure out
357+
// how many bytes we need to skip
358+
.seek(function() {
359+
return this.seekOffset - this.currentOffset;
360+
})
361+
... // the parser would continue here
362+
```
363+
364+
### seek(relOffset)
365+
Move the buffer offset for `relOffset` bytes from the current position. Use a
366+
negative `relOffset` value to rewind the offset. Previously named `skip(length)`.
367+
(Note: when encoding, the skipped bytes will be filled with zeros)
325368

326369
### endianess(endianess)
327370
Define what endianess to use in this parser. `endianess` can be either
@@ -414,9 +457,10 @@ will contain two similar parts of the code included, while with the named
414457
approach, it will include a function with a name, and will just call this
415458
function for every case of usage.
416459

417-
NB: This style could lead to circular references and infinite recursion, to
418-
avoid this, ensure that every possible path has its end. Also, this recursion
419-
is not tail-optimized, so could lead to memory leaks when it goes too deep.
460+
**Note**: This style could lead to circular references and infinite recursion,
461+
to avoid this, ensure that every possible path has its end. Also, this
462+
recursion is not tail-optimized, so could lead to memory leaks when it goes
463+
too deep.
420464

421465
An example of referencing other patches:
422466

@@ -453,10 +497,10 @@ executed for the first time.
453497

454498
### getCode() and getCodeEncode()
455499
Dynamically generates the code for this parser/encoder and returns it as a string.
456-
Usually used for debugging.
500+
Useful for debugging the generated code.
457501

458502
### Common options
459-
These are common options that can be specified in all parsers.
503+
These options can be used in all parsers.
460504

461505
- `formatter` - Function that transforms the parsed value into a more desired
462506
form. *formatter*(value, obj, buffer, offset) &rarr; *new value* \
@@ -513,11 +557,10 @@ These are common options that can be specified in all parsers.
513557
```
514558

515559
## Examples
516-
See `example` for more complex examples.
560+
See `example/` for real-world examples.
517561

518562
## Support
519563
Please report issues to the
520-
[issue tracker](https://github.com/Keichi/binary-parser/issues) if you have
564+
[issue tracker](https://github.com/keichi/binary-parser/issues) if you have
521565
any difficulties using this module, found a bug, or request a new feature.
522-
523-
Pull requests with fixes and improvements are welcomed!
566+
Pull requests are welcomed.

0 commit comments

Comments
 (0)