typespeed 2.0.13 → 2.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core.decorator.js +0 -1
- package/dist/database.decorator.js +0 -1
- package/dist/default/express-server.class.js +0 -1
- package/dist/default/log-default.class.js +0 -1
- package/dist/default/node-cache.class.js +0 -1
- package/dist/default/rabbitmq.class.js +0 -1
- package/dist/default/read-write-db.class.js +0 -1
- package/dist/default/redis.class.js +0 -1
- package/dist/factory/cache-factory.class.js +0 -1
- package/dist/factory/data-source-factory.class.js +0 -1
- package/dist/factory/log-factory.class.js +0 -1
- package/dist/factory/server-factory.class.js +0 -1
- package/dist/route.decorator.js +0 -1
- package/dist/scaffold/command.js +0 -1
- package/dist/typespeed.d.ts +133 -12
- package/dist/typespeed.js +1 -1
- package/package.json +2 -2
- package/src/typespeed.d.ts +133 -0
- package/src/typespeed.ts +2 -1
- package/test/node_modules/.package-lock.json +112 -4
- package/test/node_modules/@acuminous/bitsyntax/.github/workflows/node-js-ci.yml +17 -0
- package/test/node_modules/@acuminous/bitsyntax/.github/workflows/node-js-publish.yml +30 -0
- package/test/node_modules/@acuminous/bitsyntax/LICENSE +6 -0
- package/test/node_modules/@acuminous/bitsyntax/LICENSE-MIT +21 -0
- package/test/node_modules/@acuminous/bitsyntax/Makefile +15 -0
- package/test/node_modules/@acuminous/bitsyntax/README.md +308 -0
- package/test/node_modules/@acuminous/bitsyntax/index.js +10 -0
- package/test/node_modules/@acuminous/bitsyntax/lib/compile.js +303 -0
- package/test/node_modules/@acuminous/bitsyntax/lib/constructor.js +142 -0
- package/test/node_modules/@acuminous/bitsyntax/lib/grammar.pegjs +67 -0
- package/test/node_modules/@acuminous/bitsyntax/lib/interp.js +232 -0
- package/test/node_modules/@acuminous/bitsyntax/lib/parse.js +32 -0
- package/test/node_modules/@acuminous/bitsyntax/lib/parser.js +1173 -0
- package/test/node_modules/@acuminous/bitsyntax/lib/pattern.js +119 -0
- package/test/node_modules/@acuminous/bitsyntax/package.json +36 -0
- package/test/node_modules/@acuminous/bitsyntax/test/consing.test.js +50 -0
- package/test/node_modules/@acuminous/bitsyntax/test/matching.test.js +193 -0
- package/test/node_modules/@types/node/README.md +1 -1
- package/test/node_modules/@types/node/buffer.d.ts +5 -2
- package/test/node_modules/@types/node/child_process.d.ts +27 -0
- package/test/node_modules/@types/node/globals.d.ts +1 -0
- package/test/node_modules/@types/node/package.json +2 -2
- package/test/node_modules/@types/node/test.d.ts +43 -20
- package/test/node_modules/@types/node/ts4.8/buffer.d.ts +5 -2
- package/test/node_modules/@types/node/ts4.8/child_process.d.ts +27 -0
- package/test/node_modules/@types/node/ts4.8/globals.d.ts +1 -0
- package/test/node_modules/@types/node/ts4.8/test.d.ts +43 -19
- package/test/node_modules/@types/node/ts4.8/url.d.ts +3 -3
- package/test/node_modules/@types/node/ts4.8/util.d.ts +1 -1
- package/test/node_modules/@types/node/url.d.ts +3 -3
- package/test/node_modules/@types/node/util.d.ts +1 -1
- package/test/node_modules/amqplib/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- package/test/node_modules/amqplib/.github/workflows/test.yml +38 -0
- package/test/node_modules/amqplib/CHANGELOG.md +430 -0
- package/test/node_modules/amqplib/LICENSE +6 -0
- package/test/node_modules/amqplib/LICENSE-MIT +21 -0
- package/test/node_modules/amqplib/Makefile +47 -0
- package/test/node_modules/amqplib/README.md +157 -0
- package/test/node_modules/amqplib/bin/generate-defs.js +722 -0
- package/test/node_modules/amqplib/callback_api.js +22 -0
- package/test/node_modules/amqplib/channel_api.js +16 -0
- package/test/node_modules/amqplib/examples/headers.js +42 -0
- package/test/node_modules/amqplib/examples/receive_generator.js +39 -0
- package/test/node_modules/amqplib/examples/send_generators.js +42 -0
- package/test/node_modules/amqplib/examples/ssl.js +64 -0
- package/test/node_modules/amqplib/examples/tutorials/README.md +93 -0
- package/test/node_modules/amqplib/examples/tutorials/callback_api/emit_log.js +28 -0
- package/test/node_modules/amqplib/examples/tutorials/callback_api/emit_log_direct.js +30 -0
- package/test/node_modules/amqplib/examples/tutorials/callback_api/emit_log_topic.js +27 -0
- package/test/node_modules/amqplib/examples/tutorials/callback_api/new_task.js +27 -0
- package/test/node_modules/amqplib/examples/tutorials/callback_api/receive.js +30 -0
- package/test/node_modules/amqplib/examples/tutorials/callback_api/receive_logs.js +36 -0
- package/test/node_modules/amqplib/examples/tutorials/callback_api/receive_logs_direct.js +56 -0
- package/test/node_modules/amqplib/examples/tutorials/callback_api/receive_logs_topic.js +55 -0
- package/test/node_modules/amqplib/examples/tutorials/callback_api/rpc_client.js +49 -0
- package/test/node_modules/amqplib/examples/tutorials/callback_api/rpc_server.js +45 -0
- package/test/node_modules/amqplib/examples/tutorials/callback_api/send.js +29 -0
- package/test/node_modules/amqplib/examples/tutorials/callback_api/worker.js +35 -0
- package/test/node_modules/amqplib/examples/tutorials/emit_log.js +19 -0
- package/test/node_modules/amqplib/examples/tutorials/emit_log_direct.js +20 -0
- package/test/node_modules/amqplib/examples/tutorials/emit_log_topic.js +19 -0
- package/test/node_modules/amqplib/examples/tutorials/new_task.js +18 -0
- package/test/node_modules/amqplib/examples/tutorials/package.json +16 -0
- package/test/node_modules/amqplib/examples/tutorials/receive.js +21 -0
- package/test/node_modules/amqplib/examples/tutorials/receive_logs.js +28 -0
- package/test/node_modules/amqplib/examples/tutorials/receive_logs_direct.js +44 -0
- package/test/node_modules/amqplib/examples/tutorials/receive_logs_topic.js +43 -0
- package/test/node_modules/amqplib/examples/tutorials/rpc_client.js +52 -0
- package/test/node_modules/amqplib/examples/tutorials/rpc_server.js +39 -0
- package/test/node_modules/amqplib/examples/tutorials/send.js +23 -0
- package/test/node_modules/amqplib/examples/tutorials/worker.js +28 -0
- package/test/node_modules/amqplib/examples/waitForConfirms.js +22 -0
- package/test/node_modules/amqplib/lib/api_args.js +314 -0
- package/test/node_modules/amqplib/lib/bitset.js +130 -0
- package/test/node_modules/amqplib/lib/callback_model.js +327 -0
- package/test/node_modules/amqplib/lib/channel.js +499 -0
- package/test/node_modules/amqplib/lib/channel_model.js +302 -0
- package/test/node_modules/amqplib/lib/codec.js +321 -0
- package/test/node_modules/amqplib/lib/connect.js +189 -0
- package/test/node_modules/amqplib/lib/connection.js +663 -0
- package/test/node_modules/amqplib/lib/credentials.js +42 -0
- package/test/node_modules/amqplib/lib/defs.js +4966 -0
- package/test/node_modules/amqplib/lib/error.js +24 -0
- package/test/node_modules/amqplib/lib/format.js +40 -0
- package/test/node_modules/amqplib/lib/frame.js +113 -0
- package/test/node_modules/amqplib/lib/heartbeat.js +89 -0
- package/test/node_modules/amqplib/lib/mux.js +129 -0
- package/test/node_modules/amqplib/package.json +37 -0
- package/test/node_modules/amqplib/test/bitset.js +69 -0
- package/test/node_modules/amqplib/test/callback_api.js +312 -0
- package/test/node_modules/amqplib/test/channel.js +621 -0
- package/test/node_modules/amqplib/test/channel_api.js +596 -0
- package/test/node_modules/amqplib/test/codec.js +237 -0
- package/test/node_modules/amqplib/test/connect.js +197 -0
- package/test/node_modules/amqplib/test/connection.js +390 -0
- package/test/node_modules/amqplib/test/data.js +254 -0
- package/test/node_modules/amqplib/test/frame.js +198 -0
- package/test/node_modules/amqplib/test/mux.js +204 -0
- package/test/node_modules/amqplib/test/util.js +219 -0
- package/test/node_modules/buffer-more-ints/.travis.yml +6 -0
- package/test/node_modules/buffer-more-ints/LICENSE +19 -0
- package/test/node_modules/buffer-more-ints/README.md +69 -0
- package/test/node_modules/buffer-more-ints/buffer-more-ints-tests.js +183 -0
- package/test/node_modules/buffer-more-ints/buffer-more-ints.js +432 -0
- package/test/node_modules/buffer-more-ints/package.json +19 -0
- package/test/node_modules/buffer-more-ints/polyfill.js +71 -0
- package/test/node_modules/core-util-is/LICENSE +19 -0
- package/test/node_modules/core-util-is/README.md +3 -0
- package/test/node_modules/core-util-is/lib/util.js +107 -0
- package/test/node_modules/core-util-is/package.json +38 -0
- package/test/node_modules/debug/LICENSE +20 -0
- package/test/node_modules/debug/README.md +481 -0
- package/test/node_modules/debug/package.json +59 -0
- package/test/node_modules/debug/src/browser.js +269 -0
- package/test/node_modules/debug/src/common.js +274 -0
- package/test/node_modules/debug/src/index.js +10 -0
- package/test/node_modules/debug/src/node.js +263 -0
- package/test/node_modules/inherits/LICENSE +16 -0
- package/test/node_modules/inherits/README.md +42 -0
- package/test/node_modules/inherits/inherits.js +9 -0
- package/test/node_modules/inherits/inherits_browser.js +27 -0
- package/test/node_modules/inherits/package.json +29 -0
- package/test/node_modules/isarray/README.md +54 -0
- package/test/node_modules/isarray/build/build.js +209 -0
- package/test/node_modules/isarray/component.json +19 -0
- package/test/node_modules/isarray/index.js +3 -0
- package/test/node_modules/isarray/package.json +25 -0
- package/test/node_modules/ms/index.js +162 -0
- package/test/node_modules/ms/license.md +21 -0
- package/test/node_modules/ms/package.json +37 -0
- package/test/node_modules/ms/readme.md +60 -0
- package/test/node_modules/querystringify/LICENSE +22 -0
- package/test/node_modules/querystringify/README.md +61 -0
- package/test/node_modules/querystringify/index.js +118 -0
- package/test/node_modules/querystringify/package.json +38 -0
- package/test/node_modules/readable-stream/LICENSE +18 -0
- package/test/node_modules/readable-stream/README.md +15 -0
- package/test/node_modules/readable-stream/duplex.js +1 -0
- package/test/node_modules/readable-stream/float.patch +923 -0
- package/test/node_modules/readable-stream/lib/_stream_duplex.js +89 -0
- package/test/node_modules/readable-stream/lib/_stream_passthrough.js +46 -0
- package/test/node_modules/readable-stream/lib/_stream_readable.js +951 -0
- package/test/node_modules/readable-stream/lib/_stream_transform.js +209 -0
- package/test/node_modules/readable-stream/lib/_stream_writable.js +477 -0
- package/test/node_modules/readable-stream/package.json +32 -0
- package/test/node_modules/readable-stream/passthrough.js +1 -0
- package/test/node_modules/readable-stream/readable.js +10 -0
- package/test/node_modules/readable-stream/transform.js +1 -0
- package/test/node_modules/readable-stream/writable.js +1 -0
- package/test/node_modules/requires-port/.travis.yml +19 -0
- package/test/node_modules/requires-port/LICENSE +22 -0
- package/test/node_modules/requires-port/README.md +47 -0
- package/test/node_modules/requires-port/index.js +38 -0
- package/test/node_modules/requires-port/package.json +47 -0
- package/test/node_modules/requires-port/test.js +98 -0
- package/test/node_modules/safe-buffer/LICENSE +21 -0
- package/test/node_modules/safe-buffer/README.md +584 -0
- package/test/node_modules/safe-buffer/index.d.ts +187 -0
- package/test/node_modules/safe-buffer/index.js +62 -0
- package/test/node_modules/safe-buffer/package.json +37 -0
- package/test/node_modules/string_decoder/LICENSE +20 -0
- package/test/node_modules/string_decoder/README.md +7 -0
- package/test/node_modules/string_decoder/index.js +221 -0
- package/test/node_modules/string_decoder/package.json +25 -0
- package/test/node_modules/url-parse/LICENSE +22 -0
- package/test/node_modules/url-parse/README.md +153 -0
- package/test/node_modules/url-parse/dist/url-parse.js +755 -0
- package/test/node_modules/url-parse/dist/url-parse.min.js +1 -0
- package/test/node_modules/url-parse/dist/url-parse.min.js.map +1 -0
- package/test/node_modules/url-parse/index.js +589 -0
- package/test/node_modules/url-parse/package.json +49 -0
- package/test/src/test-mq.class.ts +1 -2
- package/tsconfig.json +4 -3
- package/dist/core.decorator.d.ts +0 -18
- package/dist/core.decorator.js.map +0 -1
- package/dist/database.decorator.d.ts +0 -24
- package/dist/database.decorator.js.map +0 -1
- package/dist/default/express-server.class.d.ts +0 -15
- package/dist/default/express-server.class.js.map +0 -1
- package/dist/default/log-default.class.d.ts +0 -6
- package/dist/default/log-default.class.js.map +0 -1
- package/dist/default/node-cache.class.d.ts +0 -13
- package/dist/default/node-cache.class.js.map +0 -1
- package/dist/default/rabbitmq.class.d.ts +0 -9
- package/dist/default/rabbitmq.class.js.map +0 -1
- package/dist/default/read-write-db.class.d.ts +0 -10
- package/dist/default/read-write-db.class.js.map +0 -1
- package/dist/default/redis.class.d.ts +0 -5
- package/dist/default/redis.class.js.map +0 -1
- package/dist/factory/cache-factory.class.d.ts +0 -7
- package/dist/factory/cache-factory.class.js.map +0 -1
- package/dist/factory/data-source-factory.class.d.ts +0 -4
- package/dist/factory/data-source-factory.class.js.map +0 -1
- package/dist/factory/log-factory.class.d.ts +0 -4
- package/dist/factory/log-factory.class.js.map +0 -1
- package/dist/factory/server-factory.class.d.ts +0 -6
- package/dist/factory/server-factory.class.js.map +0 -1
- package/dist/route.decorator.d.ts +0 -8
- package/dist/route.decorator.js.map +0 -1
- package/dist/scaffold/command.d.ts +0 -2
- package/dist/scaffold/command.js.map +0 -1
- package/dist/typespeed.js.map +0 -1
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# Byte-wise matching for Node.JS
|
|
2
|
+
|
|
3
|
+
[](https://github.com/acuminous/bitsyntax-js/actions?query=workflow%3A%22Node.js+CI%22)
|
|
4
|
+
[](https://www.npmjs.com/package/@acuminous/bitsyntax)
|
|
5
|
+
[](https://www.npmjs.com/package/@acuminous/bitsyntax)
|
|
6
|
+
|
|
7
|
+
Gives a compact syntax for parsing and constructing byte buffers,
|
|
8
|
+
derived from [Erlang's bit
|
|
9
|
+
syntax](http://www.erlang.org/doc/programming_examples/bit_syntax.html#id64858).
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
var bitsyntax = require('bitsyntax');
|
|
13
|
+
var pattern = bitsyntax.matcher('len:8/integer, str:len/binary');
|
|
14
|
+
var bound = pattern(new Buffer([4, 0x41, 0x42, 0x43, 0x44]));
|
|
15
|
+
bound.str
|
|
16
|
+
// => <Buffer 41 42 43 44>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
A typical use of this is parsing byte streams from sockets. For
|
|
20
|
+
example, size-prefixed frames:
|
|
21
|
+
|
|
22
|
+
```js
|
|
23
|
+
var framePattern = bitsyntax.matcher('len:32/integer, frame:len/binary, rest/binary');
|
|
24
|
+
socket.on('data', function process(data) {
|
|
25
|
+
var m;
|
|
26
|
+
if (m = framePattern(data)) {
|
|
27
|
+
emit('frame', m.frame);
|
|
28
|
+
process(m.rest);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
stashForNextData(data);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Patterns can also be used to construct byte buffers from supplied
|
|
37
|
+
values:
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
var spdyDataFrame = require('bitsyntax')
|
|
41
|
+
.builder('streamId:32, flags:8, length:24, data/binary');
|
|
42
|
+
|
|
43
|
+
spdyDataFrame({streamId:5, flags:0, length:bin.length, data:bin});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
One or more segments of a pattern may also be supplied in multiple
|
|
47
|
+
arguments, if that is more convenient; this makes it easier to split a
|
|
48
|
+
long pattern over lines:
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
var p = bitsyntax.matcher('size:8, payload:size/binary',
|
|
52
|
+
'rest/binary');
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## API
|
|
56
|
+
|
|
57
|
+
### `matcher`
|
|
58
|
+
|
|
59
|
+
Compiles a pattern as a string (or strings), to a function that will
|
|
60
|
+
return either a map of bindings, or `false`, given a buffer and
|
|
61
|
+
optionally an environment. The environment contains values for bound
|
|
62
|
+
variables in the pattern (if there are any).
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
var p = bitsyntax.matcher('header:headerSize/binary, rest/binary');
|
|
66
|
+
var b = p(new Buffer([1, 2, 3, 4, 5]), {headerSize: 3});
|
|
67
|
+
b.header
|
|
68
|
+
// => <Buffer 01 02 03>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
A matcher will return `false` if the supplied buffer does not match
|
|
72
|
+
the pattern; for example, if it has too few bytes, or a literal is not
|
|
73
|
+
present.
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
var p = bitsyntax.matcher('"foo=", str/binary');
|
|
77
|
+
p(new Buffer("bar=humbug"));
|
|
78
|
+
// => false
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### `parse` and `match`
|
|
82
|
+
|
|
83
|
+
When composed, equivalent to `matcher`; may be useful if you want to
|
|
84
|
+
examine the internal structure of patterns.
|
|
85
|
+
|
|
86
|
+
`parse` takes strings as for `matcher`, and returns the internal
|
|
87
|
+
representation of the pattern. `match` takes this representation, a
|
|
88
|
+
buffer, and optionally an environment, and returns the bindings or
|
|
89
|
+
`false` (as with `matcher`).
|
|
90
|
+
|
|
91
|
+
```js
|
|
92
|
+
var p = bitsyntax.parse('header:headerSize/binary',
|
|
93
|
+
'rest/binary');
|
|
94
|
+
var b = bitsyntax.match(p, new Buffer([1, 2, 3, 4, 5]),
|
|
95
|
+
{headerSize: 3});
|
|
96
|
+
b.header
|
|
97
|
+
// => <Buffer 01 02 03>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### `builder`
|
|
101
|
+
|
|
102
|
+
Takes a pattern and returns a function that will construct a byte
|
|
103
|
+
buffer, given values for the variables mentioned in the pattern.
|
|
104
|
+
|
|
105
|
+
```js
|
|
106
|
+
var cons = bitsyntax.builder('size:8, bin/binary');
|
|
107
|
+
cons({size:6, bin:new Buffer('foobar')});
|
|
108
|
+
// => <Buffer 06 66 6f 6f 62 61 72>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Patterns supplied to builders are slightly different to patterns
|
|
112
|
+
supplied for matching, as noted below.
|
|
113
|
+
|
|
114
|
+
### `build`
|
|
115
|
+
|
|
116
|
+
Takes a parsed pattern and a map of variable values, and returns a
|
|
117
|
+
buffer. As with `match`, may be useful to debug patterns.
|
|
118
|
+
|
|
119
|
+
```js
|
|
120
|
+
var pattern = bitsyntax.parse('size:8, bin:size/binary');
|
|
121
|
+
bitsyntax.build(pattern, {size:6, bin: new Buffer('foobar')});
|
|
122
|
+
// => <Buffer 06 66 6f 6f 62 61 72>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### `write`
|
|
126
|
+
|
|
127
|
+
Writes variable values into a buffer, at an offset, according to the
|
|
128
|
+
parsed pattern given. Returns the finishing offset, i.e., the supplied
|
|
129
|
+
offset plus the number of bytes written.
|
|
130
|
+
|
|
131
|
+
```js
|
|
132
|
+
var pattern = bitsyntax.parse('size:8, bin/binary');
|
|
133
|
+
var buf = new Buffer(7);
|
|
134
|
+
bitsyntax.write(buf, 0, pattern,
|
|
135
|
+
{size:6, bin: new Buffer('foobar')});
|
|
136
|
+
// => 7
|
|
137
|
+
buf
|
|
138
|
+
// => <Buffer 06 66 6f 6f 62 61 72>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Patterns
|
|
142
|
+
|
|
143
|
+
Patterns are sequences of segments, each matching a value. Segments
|
|
144
|
+
have the general form
|
|
145
|
+
|
|
146
|
+
value:size/type_specifier_list
|
|
147
|
+
|
|
148
|
+
The size and type specifier list may be omitted, giving three extra
|
|
149
|
+
variations:
|
|
150
|
+
|
|
151
|
+
value
|
|
152
|
+
value:size
|
|
153
|
+
value/type_specifier_list
|
|
154
|
+
|
|
155
|
+
The type specifier list is a list of keywords separated by
|
|
156
|
+
hyphens. Type specifiers are described below.
|
|
157
|
+
|
|
158
|
+
Patterns are generally supplied as strings, with a comma-separated
|
|
159
|
+
series of segments.
|
|
160
|
+
|
|
161
|
+
### Variable or value
|
|
162
|
+
|
|
163
|
+
The first part of a segment gives a variable name or a literal
|
|
164
|
+
value. If a variable name is given, the value matched by the segment
|
|
165
|
+
will be bound to that variable name for the rest of the pattern. If a
|
|
166
|
+
literal value is given, the matched value must equal that value. If a
|
|
167
|
+
variable's value is given in the environment, the matched value must
|
|
168
|
+
equal the provided value.
|
|
169
|
+
|
|
170
|
+
When used in a builder, the literal value will be copied into the
|
|
171
|
+
buffer according to the type it is given. A variable name indicates a
|
|
172
|
+
slot into which a value supplied to the builder will be copied.
|
|
173
|
+
|
|
174
|
+
The special variable name `_` discards the value matched; i.e., it
|
|
175
|
+
simply skips over the appropriate number of bits in the input. '_' is
|
|
176
|
+
not allowed in builder patterns.
|
|
177
|
+
|
|
178
|
+
### Size and unit
|
|
179
|
+
|
|
180
|
+
The size of a segment is given following the value or variable,
|
|
181
|
+
separated with a colon:
|
|
182
|
+
|
|
183
|
+
foo:32
|
|
184
|
+
|
|
185
|
+
The unit is given in the list of specifiers as `'unit' and
|
|
186
|
+
an integer from 0..256, separated by a colon:
|
|
187
|
+
|
|
188
|
+
foo:4/integer-unit:8
|
|
189
|
+
|
|
190
|
+
The size is the number of units in the value; the unit is given as a
|
|
191
|
+
number of bits. Unit can be of use, for example, when you want to
|
|
192
|
+
match integers of a number of bytes rather than a number of bits.
|
|
193
|
+
|
|
194
|
+
For integers and floats, the default unit is 1 bit; to keep things
|
|
195
|
+
aligned on byte boundaries, `unit * size` must currently be a multiple
|
|
196
|
+
of 8. For binaries the default unit is 8, and the unit must be a
|
|
197
|
+
multiple of 8.
|
|
198
|
+
|
|
199
|
+
If the size is omitted and the type is integer, the size defaults to
|
|
200
|
+
8. If the size is omitted and the type is binary, the segment will
|
|
201
|
+
match all remaining bytes in the input; such a segment may only be
|
|
202
|
+
used at the end of a pattern, when matching.
|
|
203
|
+
|
|
204
|
+
The size may also be given as an integer variable matched earlier in
|
|
205
|
+
the pattern, as in the example given at the top. When constructing, a
|
|
206
|
+
size may be a variable referring to the supplied environment.
|
|
207
|
+
|
|
208
|
+
In builders, numbers will be rounded, masked or padded to fit the size
|
|
209
|
+
and units given; for example, `'256:8'` gives the binary `Buffer<00>`
|
|
210
|
+
because the lowest eight bits are 0; `'255:16` gives the binary
|
|
211
|
+
`Buffer<00 ff>`.
|
|
212
|
+
|
|
213
|
+
### Type name specifier
|
|
214
|
+
|
|
215
|
+
One of `integer`, `binary`, `string`, `float`. If not given, the
|
|
216
|
+
default is `integer`.
|
|
217
|
+
|
|
218
|
+
An integer is a big- or little-endian, signed or unsigned
|
|
219
|
+
integer. Integers up to 32 bits are supported. Signed integers are
|
|
220
|
+
two's complement format. In JavaScript, only integers between -(2^53)
|
|
221
|
+
and 2^53 can be represented, and bitwise operators are only defined on
|
|
222
|
+
32-bit signed integers.
|
|
223
|
+
|
|
224
|
+
A binary is simply a byte buffer; usually this will result in a slice
|
|
225
|
+
of the input buffer being returned, so beware mutation.
|
|
226
|
+
|
|
227
|
+
A string is a UTF8 string consisting of the given number of bytes.
|
|
228
|
+
|
|
229
|
+
A float is a 32- or 64-bit IEEE754 floating-point value (this is the
|
|
230
|
+
standard JavaScript uses, as do Java and Erlang).
|
|
231
|
+
|
|
232
|
+
### Endianness specifier
|
|
233
|
+
|
|
234
|
+
Integers may be big- or little-endian; this refers to which 'end' of
|
|
235
|
+
the bytes making up the integer are most significant. In network
|
|
236
|
+
protocols integers are usually big-endian, meaning the first
|
|
237
|
+
(left-most) byte is the most significant, but this is not always the
|
|
238
|
+
case.
|
|
239
|
+
|
|
240
|
+
A specifier of `big` means the integer will be parsed (or written into
|
|
241
|
+
the result) as big-endian, and `little` means the integer will be
|
|
242
|
+
parsed or written as little-endian. The default is big-endian.
|
|
243
|
+
|
|
244
|
+
### Signedness specifier
|
|
245
|
+
|
|
246
|
+
Integer segments may include a specifier of `signed` or `unsigned`. A
|
|
247
|
+
signed integer is parsed as two's complement format. The default is
|
|
248
|
+
unsigned.
|
|
249
|
+
|
|
250
|
+
Signedness is ignored in builders.
|
|
251
|
+
|
|
252
|
+
### Literal strings
|
|
253
|
+
|
|
254
|
+
A quoted string appearing in a pattern is a shorthand for the bytes in
|
|
255
|
+
its UTF8 encoding. For example,
|
|
256
|
+
|
|
257
|
+
"foobar", _/binary
|
|
258
|
+
|
|
259
|
+
matches any buffer that starts with the bytes `0x66, 0x6f, 0x6f, 0x62,
|
|
260
|
+
0x61, 0x72`.
|
|
261
|
+
|
|
262
|
+
When used in a builder, a quoted string is copied into the result as
|
|
263
|
+
the bytes of its UTF8 encoding.
|
|
264
|
+
|
|
265
|
+
## Examples
|
|
266
|
+
|
|
267
|
+
In the following the matched bytes are given in array notation for
|
|
268
|
+
convenience. Bear in mind that `match()` actually takes a buffer for
|
|
269
|
+
the bytes to match against. The phrase "returns X as Y" or "binds X as
|
|
270
|
+
Y" means the return value is an object with value X mapped to the key
|
|
271
|
+
Y.
|
|
272
|
+
|
|
273
|
+
54
|
|
274
|
+
|
|
275
|
+
Matches the single byte `54`.
|
|
276
|
+
|
|
277
|
+
54:32
|
|
278
|
+
|
|
279
|
+
Matches the bytes [0,0,0,54].
|
|
280
|
+
|
|
281
|
+
54:32/little
|
|
282
|
+
|
|
283
|
+
Matches the bytes [54,0,0,0].
|
|
284
|
+
|
|
285
|
+
54:4/unit:8
|
|
286
|
+
|
|
287
|
+
Matches the bytes [0,0,0,54].
|
|
288
|
+
|
|
289
|
+
int:32/signed
|
|
290
|
+
|
|
291
|
+
Matches a binary of four bytes, and returns a signed 32-bit integer as
|
|
292
|
+
`int`.
|
|
293
|
+
|
|
294
|
+
len:16, str:len/binary
|
|
295
|
+
|
|
296
|
+
Matches a binary of `2 + len` bytes, and returns an unsigned 16-bit
|
|
297
|
+
integer as `len` and a buffer of length `len` as `str`.
|
|
298
|
+
|
|
299
|
+
len:16, _:len/binary, rest/binary
|
|
300
|
+
|
|
301
|
+
Matches a binary of at least `2 + len` bytes, binds an unsigned 16-bit
|
|
302
|
+
integer as `len`, ignores the next `len` bytes, and binds the
|
|
303
|
+
remaining (possibly zero-length) binary as `rest`.
|
|
304
|
+
|
|
305
|
+
s:8, key:s/binary, value/binary
|
|
306
|
+
|
|
307
|
+
When given the environment `{s:6, key: "foobar"}`, will match a binary
|
|
308
|
+
starting with [6, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72, ...].
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
module.exports.parse = require('./lib/parse').parse;
|
|
4
|
+
module.exports.match = require('./lib/interp').match;
|
|
5
|
+
module.exports.build = require('./lib/constructor').build;
|
|
6
|
+
module.exports.write = require('./lib/constructor').write;
|
|
7
|
+
|
|
8
|
+
module.exports.matcher = module.exports.compile =
|
|
9
|
+
require('./lib/compile').compile;
|
|
10
|
+
module.exports.builder = require('./lib/compile').compile_builder;
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
// Compile patterns to recognisers and constructors
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
require('buffer-more-ints');
|
|
6
|
+
var $ = require('util').format;
|
|
7
|
+
|
|
8
|
+
var parse = require('./parse').parse;
|
|
9
|
+
var interp = require('./interp'),
|
|
10
|
+
parse_int = interp.parse_int,
|
|
11
|
+
parse_float = interp.parse_float;
|
|
12
|
+
var construct = require('./constructor'),
|
|
13
|
+
write_int = construct.write_int,
|
|
14
|
+
write_float = construct.write_float;
|
|
15
|
+
|
|
16
|
+
var Buffer = require('safe-buffer').Buffer;
|
|
17
|
+
|
|
18
|
+
var lines = [];
|
|
19
|
+
function $start() {
|
|
20
|
+
lines = [];
|
|
21
|
+
}
|
|
22
|
+
function $line(/* format , args */) {
|
|
23
|
+
lines.push($.apply(null, arguments));
|
|
24
|
+
}
|
|
25
|
+
function $result() {
|
|
26
|
+
return lines.join('\n');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function bits_expr(segment) {
|
|
30
|
+
if (typeof segment.size === 'string') {
|
|
31
|
+
return $('%s * %d', var_name(segment.size), segment.unit);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
return (segment.size * segment.unit).toString();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function get_number(segment) {
|
|
39
|
+
$line('bits = %s;\n', bits_expr(segment));
|
|
40
|
+
var parser = (segment.type === 'integer') ?
|
|
41
|
+
'parse_int' : 'parse_float';
|
|
42
|
+
var be = segment.bigendian, sg = segment.signed;
|
|
43
|
+
$line("byteoffset = offset / 8; offset += bits");
|
|
44
|
+
$line("if (offset > binsize) { return false; }");
|
|
45
|
+
$line("else { result = %s(bin, byteoffset, bits / 8, %s, %s); }",
|
|
46
|
+
parser, be, sg);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function get_binary(segment) {
|
|
50
|
+
$line("byteoffset = offset / 8;");
|
|
51
|
+
if (segment.size === true) {
|
|
52
|
+
$line("offset = binsize;");
|
|
53
|
+
$line("result = bin.slice(byteoffset);");
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
$line("bits = %s;", bits_expr(segment));
|
|
57
|
+
$line("offset += bits;");
|
|
58
|
+
$line("if (offset > binsize) { return false; }");
|
|
59
|
+
$line("else { result = bin.slice(byteoffset,",
|
|
60
|
+
"byteoffset + bits / 8); }");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function get_string(segment) {
|
|
65
|
+
$line("byteoffset = offset / 8;");
|
|
66
|
+
var strlen = segment.value.length;
|
|
67
|
+
var strlenbits = strlen * 8;
|
|
68
|
+
$line("offset += %d;", strlenbits);
|
|
69
|
+
$line("if (offset > binsize) { return false; }");
|
|
70
|
+
$line("else { result = bin.toString(byteoffset,",
|
|
71
|
+
$("byteoffset + %d); }", strlen));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function skip_bits(segment) {
|
|
75
|
+
if (typeof segment.size === 'string') {
|
|
76
|
+
// Damn. Have to look up the size.
|
|
77
|
+
$line("var skipbits = %s * %d;",
|
|
78
|
+
var_name(segment.size), segment.unit);
|
|
79
|
+
$line("if (offset + skipbits > binsize) { return false; }");
|
|
80
|
+
$line("else { offset += skipbits; }");
|
|
81
|
+
}
|
|
82
|
+
else if (segment.size === true) {
|
|
83
|
+
$line("if (offset % 8 === 0) { offset = binsize; }");
|
|
84
|
+
$line("else { return false; }");
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
var bits = segment.unit * segment.size;
|
|
88
|
+
$line("if (offset + %d > binsize) { return false; }", bits);
|
|
89
|
+
$line("else { offset += %d; }", bits);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function match_seg(segment) {
|
|
94
|
+
if (segment.name === '_') {
|
|
95
|
+
skip_bits(segment);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
var assign_result;
|
|
99
|
+
switch (segment.type) {
|
|
100
|
+
case 'integer':
|
|
101
|
+
case 'float':
|
|
102
|
+
get_number(segment);
|
|
103
|
+
break;
|
|
104
|
+
case 'binary':
|
|
105
|
+
get_binary(segment);
|
|
106
|
+
break;
|
|
107
|
+
case 'string':
|
|
108
|
+
get_string(segment);
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
$line("if (result === false) return false;");
|
|
112
|
+
if (segment.name) {
|
|
113
|
+
// variable is given a value in the environment
|
|
114
|
+
$line("else if (%s !== undefined) {", var_name(segment.name));
|
|
115
|
+
// .. and it is not the same as that matched
|
|
116
|
+
$line("if (%s != result) return false;",
|
|
117
|
+
var_name(segment.name));
|
|
118
|
+
$line("}");
|
|
119
|
+
// variable is free
|
|
120
|
+
$line('else %s = result;', var_name(segment.name));
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
var repr = JSON.stringify(segment.value);
|
|
124
|
+
$line("else if (result != %s) return false;", repr);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function var_name(name) {
|
|
130
|
+
return 'var_' + name;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function variables(segments) {
|
|
134
|
+
var names = {};
|
|
135
|
+
for (var i = 0; i < segments.length; i++) {
|
|
136
|
+
var name = segments[i].name;
|
|
137
|
+
if (name && name !== '_') {
|
|
138
|
+
names[name] = true;
|
|
139
|
+
}
|
|
140
|
+
name = segments[i].size;
|
|
141
|
+
if (typeof name === 'string') {
|
|
142
|
+
names[name] = true;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return Object.keys(names);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function compile_pattern(segments) {
|
|
149
|
+
$start();
|
|
150
|
+
$line("return function(binary, env) {");
|
|
151
|
+
$line("'use strict';");
|
|
152
|
+
$line("var bin = binary, env = env || {};");
|
|
153
|
+
$line("var offset = 0, binsize = bin.length * 8;");
|
|
154
|
+
$line("var bits, result, byteoffset;");
|
|
155
|
+
var varnames = variables(segments);
|
|
156
|
+
for (var v = 0; v < varnames.length; v++) {
|
|
157
|
+
var name = varnames[v];
|
|
158
|
+
$line("var %s = env['%s'];", var_name(name), name);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
var len = segments.length;
|
|
162
|
+
for (var i = 0; i < len; i++) {
|
|
163
|
+
var segment = segments[i];
|
|
164
|
+
$line("// " + JSON.stringify(segment));
|
|
165
|
+
match_seg(segment);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
$line("if (offset == binsize) {");
|
|
169
|
+
$line("return {");
|
|
170
|
+
for (var v = 0; v < varnames.length; v++) {
|
|
171
|
+
var name = varnames[v];
|
|
172
|
+
$line("%s: %s,", name, var_name(name));
|
|
173
|
+
}
|
|
174
|
+
$line('};');
|
|
175
|
+
$line('}'); // if offset == binsize
|
|
176
|
+
$line("else return false;");
|
|
177
|
+
$line("}"); // end function
|
|
178
|
+
|
|
179
|
+
var fn = new Function('parse_int', 'parse_float', $result());
|
|
180
|
+
return fn(parse_int, parse_float);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
function write_seg(segment) {
|
|
185
|
+
switch (segment.type) {
|
|
186
|
+
case 'string':
|
|
187
|
+
$line("offset += buf.write(%s, offset, 'utf8');",
|
|
188
|
+
JSON.stringify(segment.value));
|
|
189
|
+
break;
|
|
190
|
+
case 'binary':
|
|
191
|
+
$line("val = bindings['%s'];", segment.name);
|
|
192
|
+
if (segment.size === true) {
|
|
193
|
+
$line('size = val.length;');
|
|
194
|
+
}
|
|
195
|
+
else if (typeof segment.size === 'string') {
|
|
196
|
+
$line("size = (bindings['%s'] * %d) / 8;",
|
|
197
|
+
segment.size, segment.unit);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
$line("size = %d;", (segment.size * segment.unit) / 8);
|
|
201
|
+
}
|
|
202
|
+
$line('val.copy(buf, offset, 0, size);');
|
|
203
|
+
$line('offset += size;');
|
|
204
|
+
break;
|
|
205
|
+
case 'integer':
|
|
206
|
+
case 'float':
|
|
207
|
+
write_number(segment);
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function write_number(segment) {
|
|
213
|
+
if (segment.name) {
|
|
214
|
+
$line("val = bindings['%s'];", segment.name);
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
$line("val = %d", segment.value);
|
|
218
|
+
}
|
|
219
|
+
var writer = (segment.type === 'integer') ?
|
|
220
|
+
'write_int' : 'write_float';
|
|
221
|
+
if (typeof segment.size === 'string') {
|
|
222
|
+
$line("size = (bindings['%s'] * %d) / 8;",
|
|
223
|
+
segment.size, segment.unit);
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
$line('size = %d;', (segment.size * segment.unit) / 8);
|
|
227
|
+
}
|
|
228
|
+
$line('%s(buf, val, offset, size, %s);',
|
|
229
|
+
writer, segment.bigendian);
|
|
230
|
+
$line('offset += size;');
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function size_of(segments) {
|
|
234
|
+
var variable = [];
|
|
235
|
+
var fixed = 0;
|
|
236
|
+
|
|
237
|
+
for (var i = 0; i < segments.length; i++) {
|
|
238
|
+
var segment = segments[i];
|
|
239
|
+
if (typeof segment.size === 'string' ||
|
|
240
|
+
segment.size === true) {
|
|
241
|
+
variable.push(segment);
|
|
242
|
+
}
|
|
243
|
+
else if (segment.type === 'string') {
|
|
244
|
+
fixed += Buffer.byteLength(segment.value);
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
fixed += (segment.size * segment.unit) / 8;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
$line('var buffersize = %d;', fixed);
|
|
252
|
+
|
|
253
|
+
if (variable.length > 0) {
|
|
254
|
+
for (var j = 0; j < variable.length; j++) {
|
|
255
|
+
var segment = variable[j];
|
|
256
|
+
if (segment.size === true) {
|
|
257
|
+
$line("buffersize += bindings['%s'].length;", segment.name);
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
$line("buffersize += (bindings['%s'] * %d) / 8;",
|
|
261
|
+
segment.size, segment.unit);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function emit_write(segments) {
|
|
268
|
+
$line('var val, size;');
|
|
269
|
+
|
|
270
|
+
var len = segments.length;
|
|
271
|
+
for (var i = 0; i < len; i++) {
|
|
272
|
+
var segment = segments[i];
|
|
273
|
+
$line('// %s', JSON.stringify(segment));
|
|
274
|
+
write_seg(segment);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function compile_ctor(segments) {
|
|
279
|
+
$start();
|
|
280
|
+
$line('return function(bindings) {');
|
|
281
|
+
$line("'use strict';");
|
|
282
|
+
size_of(segments);
|
|
283
|
+
$line('var buf = Buffer.alloc(buffersize);');
|
|
284
|
+
$line('var offset = 0;');
|
|
285
|
+
emit_write(segments);
|
|
286
|
+
$line('return buf;');
|
|
287
|
+
$line('}'); // end function
|
|
288
|
+
|
|
289
|
+
return new Function('write_int', 'write_float', 'Buffer',
|
|
290
|
+
$result())(write_int, write_float, Buffer);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
module.exports.compile_pattern = compile_pattern;
|
|
294
|
+
module.exports.compile = function() {
|
|
295
|
+
var str = [].join.call(arguments, ',');
|
|
296
|
+
var p = parse(str);
|
|
297
|
+
return compile_pattern(p);
|
|
298
|
+
};
|
|
299
|
+
module.exports.compile_builder = function() {
|
|
300
|
+
var str = [].join.call(arguments, ',');
|
|
301
|
+
var p = parse(str);
|
|
302
|
+
return compile_ctor(p);
|
|
303
|
+
};
|