{"_id":"@acuminous/bitsyntax","_rev":"3618672","name":"@acuminous/bitsyntax","description":"Pattern-matching on byte buffers","dist-tags":{"latest":"0.1.2"},"maintainers":[{"name":"cressie176","email":"stephen.cresswell@gmail.com"}],"time":{"modified":"2024-10-15T06:47:50.000Z","created":"2022-09-01T06:27:27.100Z","0.1.2":"2022-09-01T06:42:09.042Z","0.1.1":"2022-09-01T06:27:27.100Z"},"users":{},"author":{"name":"Michael Bridgen","email":"mikeb@squaremobius.net"},"repository":{"type":"git","url":"git://github.com/acuminous/bitsyntax-js.git"},"versions":{"0.1.2":{"author":{"name":"Michael Bridgen","email":"mikeb@squaremobius.net"},"name":"@acuminous/bitsyntax","description":"Pattern-matching on byte buffers","license":"MIT","version":"0.1.2","repository":{"type":"git","url":"git://github.com/acuminous/bitsyntax-js.git"},"main":"./index","scripts":{"test":"make test","prepublish":"make all"},"engines":{"node":">=0.8"},"dependencies":{"buffer-more-ints":"~1.0.0","debug":"^4.3.4","safe-buffer":"~5.1.2"},"devDependencies":{"pegjs":"^0.7.0","zunit":"^3.2.1"},"bugs":{"url":"https://github.com/acuminous/bitsyntax-js/issues"},"homepage":"https://github.com/acuminous/bitsyntax-js#readme","directories":{"lib":"lib","test":"test"},"gitHead":"f75397772a9794dd123511ada2218f350c1ceec2","_id":"@acuminous/bitsyntax@0.1.2","_nodeVersion":"16.17.0","_npmVersion":"8.15.0","dist":{"shasum":"e0b31b9ee7ad1e4dd840c34864327c33d9f1f653","size":17552,"noattachment":false,"key":"/@acuminous/bitsyntax/-/@acuminous/bitsyntax-0.1.2.tgz","tarball":"http://registry.cnpm.dingdandao.com/@acuminous/bitsyntax/download/@acuminous/bitsyntax-0.1.2.tgz"},"_npmUser":{"name":"cressie176","email":"stephen.cresswell@gmail.com"},"maintainers":[{"name":"cressie176","email":"stephen.cresswell@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/bitsyntax_0.1.2_1662014528810_0.24977226054248525"},"_hasShrinkwrap":false,"_cnpmcore_publish_time":"2022-09-01T06:43:22.355Z","publish_time":1662014529042,"_cnpm_publish_time":1662014529042},"0.1.1":{"author":{"name":"Michael Bridgen","email":"mikeb@squaremobius.net"},"name":"@acuminous/bitsyntax","description":"Pattern-matching on byte buffers","license":"MIT","version":"0.1.1","repository":{"type":"git","url":"git://github.com/squaremo/bitsyntax-js.git"},"main":"./index","scripts":{"test":"make test","prepublish":"make all"},"engines":{"node":">=0.8"},"dependencies":{"buffer-more-ints":"~1.0.0","debug":"^4.3.4","safe-buffer":"~5.1.2"},"devDependencies":{"pegjs":"^0.7.0","zunit":"^3.2.1"},"gitHead":"e102b25e7e4f84da19a860cd8b5ec4bd66ad7e69","bugs":{"url":"https://github.com/squaremo/bitsyntax-js/issues"},"homepage":"https://github.com/squaremo/bitsyntax-js#readme","_id":"@acuminous/bitsyntax@0.1.1","_nodeVersion":"16.17.0","_npmVersion":"8.15.0","dist":{"shasum":"d8a2925ed7c21ab1206635067f65b25ffc383eb2","size":17514,"noattachment":false,"key":"/@acuminous/bitsyntax/-/@acuminous/bitsyntax-0.1.1.tgz","tarball":"http://registry.cnpm.dingdandao.com/@acuminous/bitsyntax/download/@acuminous/bitsyntax-0.1.1.tgz"},"_npmUser":{"name":"cressie176","email":"stephen.cresswell@gmail.com"},"directories":{},"maintainers":[{"name":"cressie176","email":"stephen.cresswell@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/bitsyntax_0.1.1_1662013646922_0.9241962382535758"},"_hasShrinkwrap":false,"_cnpmcore_publish_time":"2022-09-01T06:27:40.129Z","publish_time":1662013647100,"_cnpm_publish_time":1662013647100}},"readme":"# Byte-wise matching for Node.JS\n\n[![Node.js CI](https://github.com/acuminous/bitsyntax-js/workflows/Node.js%20CI/badge.svg)](https://github.com/acuminous/bitsyntax-js/actions?query=workflow%3A%22Node.js+CI%22)\n[![NPM version](https://img.shields.io/npm/v/bitsyntax.svg?style=flat-square)](https://www.npmjs.com/package/@acuminous/bitsyntax)\n[![NPM downloads](https://img.shields.io/npm/dm/bitsyntax.svg?style=flat-square)](https://www.npmjs.com/package/@acuminous/bitsyntax)\n\nGives a compact syntax for parsing and constructing byte buffers,\nderived from [Erlang's bit\nsyntax](http://www.erlang.org/doc/programming_examples/bit_syntax.html#id64858).\n\n```js\nvar bitsyntax = require('bitsyntax');\nvar pattern = bitsyntax.matcher('len:8/integer, str:len/binary');\nvar bound = pattern(new Buffer([4, 0x41, 0x42, 0x43, 0x44]));\nbound.str\n// => <Buffer 41 42 43 44>\n```\n\nA typical use of this is parsing byte streams from sockets. For\nexample, size-prefixed frames:\n\n```js\nvar framePattern = bitsyntax.matcher('len:32/integer, frame:len/binary, rest/binary');\nsocket.on('data', function process(data) {\n  var m;\n  if (m = framePattern(data)) {\n    emit('frame', m.frame);\n    process(m.rest);\n  }\n  else {\n    stashForNextData(data);\n  }\n});\n```\n\nPatterns can also be used to construct byte buffers from supplied\nvalues:\n\n```js\nvar spdyDataFrame = require('bitsyntax')\n  .builder('streamId:32, flags:8, length:24, data/binary');\n\nspdyDataFrame({streamId:5, flags:0, length:bin.length, data:bin});\n```\n\nOne or more segments of a pattern may also be supplied in multiple\narguments, if that is more convenient; this makes it easier to split a\nlong pattern over lines:\n\n```js\nvar p = bitsyntax.matcher('size:8, payload:size/binary',\n                          'rest/binary');\n```\n\n## API\n\n### `matcher`\n\nCompiles a pattern as a string (or strings), to a function that will\nreturn either a map of bindings, or `false`, given a buffer and\noptionally an environment. The environment contains values for bound\nvariables in the pattern (if there are any).\n\n```js\nvar p = bitsyntax.matcher('header:headerSize/binary, rest/binary');\nvar b = p(new Buffer([1, 2, 3, 4, 5]), {headerSize: 3});\nb.header\n// => <Buffer 01 02 03>\n```\n\nA matcher will return `false` if the supplied buffer does not match\nthe pattern; for example, if it has too few bytes, or a literal is not\npresent.\n\n```js\nvar p = bitsyntax.matcher('\"foo=\", str/binary');\np(new Buffer(\"bar=humbug\"));\n// => false\n```\n\n### `parse` and `match`\n\nWhen composed, equivalent to `matcher`; may be useful if you want to\nexamine the internal structure of patterns.\n\n`parse` takes strings as for `matcher`, and returns the internal\nrepresentation of the pattern. `match` takes this representation, a\nbuffer, and optionally an environment, and returns the bindings or\n`false` (as with `matcher`).\n\n```js\nvar p = bitsyntax.parse('header:headerSize/binary',\n                        'rest/binary');\nvar b = bitsyntax.match(p, new Buffer([1, 2, 3, 4, 5]),\n                          {headerSize: 3});\nb.header\n// => <Buffer 01 02 03>\n```\n\n### `builder`\n\nTakes a pattern and returns a function that will construct a byte\nbuffer, given values for the variables mentioned in the pattern.\n\n```js\nvar cons = bitsyntax.builder('size:8, bin/binary');\ncons({size:6, bin:new Buffer('foobar')});\n// => <Buffer 06 66 6f 6f 62 61 72>\n```\n\nPatterns supplied to builders are slightly different to patterns\nsupplied for matching, as noted below.\n\n### `build`\n\nTakes a parsed pattern and a map of variable values, and returns a\nbuffer. As with `match`, may be useful to debug patterns.\n\n```js\nvar pattern = bitsyntax.parse('size:8, bin:size/binary');\nbitsyntax.build(pattern, {size:6, bin: new Buffer('foobar')});\n// => <Buffer 06 66 6f 6f 62 61 72>\n```\n\n### `write`\n\nWrites variable values into a buffer, at an offset, according to the\nparsed pattern given. Returns the finishing offset, i.e., the supplied\noffset plus the number of bytes written.\n\n```js\nvar pattern = bitsyntax.parse('size:8, bin/binary');\nvar buf = new Buffer(7);\nbitsyntax.write(buf, 0, pattern,\n                {size:6, bin: new Buffer('foobar')});\n// => 7\nbuf\n// => <Buffer 06 66 6f 6f 62 61 72>\n```\n\n## Patterns\n\nPatterns are sequences of segments, each matching a value. Segments\nhave the general form\n\n     value:size/type_specifier_list\n\nThe size and type specifier list may be omitted, giving three extra\nvariations:\n\n    value\n    value:size\n    value/type_specifier_list\n\nThe type specifier list is a list of keywords separated by\nhyphens. Type specifiers are described below.\n\nPatterns are generally supplied as strings, with a comma-separated\nseries of segments.\n\n### Variable or value\n\nThe first part of a segment gives a variable name or a literal\nvalue. If a variable name is given, the value matched by the segment\nwill be bound to that variable name for the rest of the pattern. If a\nliteral value is given, the matched value must equal that value. If a\nvariable's value is given in the environment, the matched value must\nequal the provided value.\n\nWhen used in a builder, the literal value will be copied into the\nbuffer according to the type it is given. A variable name indicates a\nslot into which a value supplied to the builder will be copied.\n\nThe special variable name `_` discards the value matched; i.e., it\nsimply skips over the appropriate number of bits in the input. '_' is\nnot allowed in builder patterns.\n\n### Size and unit\n\nThe size of a segment is given following the value or variable,\nseparated with a colon:\n\n    foo:32\n\nThe unit is given in the list of specifiers as `'unit' and\nan integer from 0..256, separated by a colon:\n\n    foo:4/integer-unit:8\n\nThe size is the number of units in the value; the unit is given as a\nnumber of bits. Unit can be of use, for example, when you want to\nmatch integers of a number of bytes rather than a number of bits.\n\nFor integers and floats, the default unit is 1 bit; to keep things\naligned on byte boundaries, `unit * size` must currently be a multiple\nof 8. For binaries the default unit is 8, and the unit must be a\nmultiple of 8.\n\nIf the size is omitted and the type is integer, the size defaults to\n8. If the size is omitted and the type is binary, the segment will\nmatch all remaining bytes in the input; such a segment may only be\nused at the end of a pattern, when matching.\n\nThe size may also be given as an integer variable matched earlier in\nthe pattern, as in the example given at the top. When constructing, a\nsize may be a variable referring to the supplied environment.\n\nIn builders, numbers will be rounded, masked or padded to fit the size\nand units given; for example, `'256:8'` gives the binary `Buffer<00>`\nbecause the lowest eight bits are 0; `'255:16` gives the binary\n`Buffer<00 ff>`.\n\n### Type name specifier\n\nOne of `integer`, `binary`, `string`, `float`. If not given, the\ndefault is `integer`.\n\nAn integer is a big- or little-endian, signed or unsigned\ninteger. Integers up to 32 bits are supported. Signed integers are\ntwo's complement format. In JavaScript, only integers between -(2^53)\nand 2^53 can be represented, and bitwise operators are only defined on\n32-bit signed integers.\n\nA binary is simply a byte buffer; usually this will result in a slice\nof the input buffer being returned, so beware mutation.\n\nA string is a UTF8 string consisting of the given number of bytes.\n\nA float is a 32- or 64-bit IEEE754 floating-point value (this is the\nstandard JavaScript uses, as do Java and Erlang).\n\n### Endianness specifier\n\nIntegers may be big- or little-endian; this refers to which 'end' of\nthe bytes making up the integer are most significant. In network\nprotocols integers are usually big-endian, meaning the first\n(left-most) byte is the most significant, but this is not always the\ncase.\n\nA specifier of `big` means the integer will be parsed (or written into\nthe result) as big-endian, and `little` means the integer will be\nparsed or written as little-endian. The default is big-endian.\n\n### Signedness specifier\n\nInteger segments may include a specifier of `signed` or `unsigned`. A\nsigned integer is parsed as two's complement format. The default is\nunsigned.\n\nSignedness is ignored in builders.\n\n### Literal strings\n\nA quoted string appearing in a pattern is a shorthand for the bytes in\nits UTF8 encoding. For example,\n\n    \"foobar\", _/binary\n\nmatches any buffer that starts with the bytes `0x66, 0x6f, 0x6f, 0x62,\n0x61, 0x72`.\n\nWhen used in a builder, a quoted string is copied into the result as\nthe bytes of its UTF8 encoding.\n\n## Examples\n\nIn the following the matched bytes are given in array notation for\nconvenience. Bear in mind that `match()` actually takes a buffer for\nthe bytes to match against. The phrase \"returns X as Y\" or \"binds X as\nY\" means the return value is an object with value X mapped to the key\nY.\n\n    54\n\nMatches the single byte `54`.\n\n    54:32\n\nMatches the bytes [0,0,0,54].\n\n    54:32/little\n\nMatches the bytes [54,0,0,0].\n\n    54:4/unit:8\n\nMatches the bytes [0,0,0,54].\n\n    int:32/signed\n\nMatches a binary of four bytes, and returns a signed 32-bit integer as\n`int`.\n\n    len:16, str:len/binary\n\nMatches a binary of `2 + len` bytes, and returns an unsigned 16-bit\ninteger as `len` and a buffer of length `len` as `str`.\n\n    len:16, _:len/binary, rest/binary\n\nMatches a binary of at least `2 + len` bytes, binds an unsigned 16-bit\ninteger as `len`, ignores the next `len` bytes, and binds the\nremaining (possibly zero-length) binary as `rest`.\n\n    s:8, key:s/binary, value/binary\n\nWhen given the environment `{s:6, key: \"foobar\"}`, will match a binary\nstarting with [6, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72, ...].\n","_attachments":{},"homepage":"https://github.com/acuminous/bitsyntax-js#readme","bugs":{"url":"https://github.com/acuminous/bitsyntax-js/issues"},"license":"MIT"}