@mapwhit/pbf 1.0.0
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/LICENSE +27 -0
- package/README.md +315 -0
- package/index.js +698 -0
- package/package.json +45 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Copyright (c) 2017, Mapbox
|
|
2
|
+
All rights reserved.
|
|
3
|
+
|
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
|
6
|
+
|
|
7
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
8
|
+
list of conditions and the following disclaimer.
|
|
9
|
+
|
|
10
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
11
|
+
this list of conditions and the following disclaimer in the documentation
|
|
12
|
+
and/or other materials provided with the distribution.
|
|
13
|
+
|
|
14
|
+
* Neither the name of pbf nor the names of its
|
|
15
|
+
contributors may be used to endorse or promote products derived from
|
|
16
|
+
this software without specific prior written permission.
|
|
17
|
+
|
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
19
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
20
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
21
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
22
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
23
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
24
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
25
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
26
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
27
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
[![NPM version][npm-image]][npm-url]
|
|
2
|
+
[![Build Status][build-image]][build-url]
|
|
3
|
+
[![Dependency Status][deps-image]][deps-url]
|
|
4
|
+
|
|
5
|
+
# @mapwhit/pbf
|
|
6
|
+
|
|
7
|
+
Fork of [pbf]
|
|
8
|
+
|
|
9
|
+
A low-level, fast, ultra-lightweight (3KB gzipped) JavaScript library for decoding and encoding [protocol buffers](https://developers.google.com/protocol-buffers), a compact binary format for structured data serialization. Works both in Node and the browser. Supports lazy decoding and detailed customization of the reading/writing code.
|
|
10
|
+
|
|
11
|
+
## Performance
|
|
12
|
+
|
|
13
|
+
This library is extremely fast — much faster than native `JSON.parse`/`JSON.stringify`
|
|
14
|
+
and the [protocol-buffers](https://github.com/mafintosh/protocol-buffers) module.
|
|
15
|
+
Here's a result from running a real-world benchmark on Node v6.5
|
|
16
|
+
(decoding and encoding a sample of 439 vector tiles, 22.6 MB total):
|
|
17
|
+
|
|
18
|
+
- **pbf** decode: 387ms, or 57 MB/s
|
|
19
|
+
- **pbf** encode: 396ms, or 56 MB/s
|
|
20
|
+
- **protocol-buffers** decode: 837ms, or 26 MB/s
|
|
21
|
+
- **protocol-buffers** encode: 4197ms, or 5 MB/s
|
|
22
|
+
- **JSON.parse**: 1540ms, or 125 MB/s (parsing an equivalent 77.5 MB JSON file)
|
|
23
|
+
- **JSON.stringify**: 607ms, or 49 MB/s
|
|
24
|
+
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
#### Using Compiled Code
|
|
28
|
+
|
|
29
|
+
Install `pbf` and compile a JavaScript module from a `.proto` file:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
$ npm install -g pbf
|
|
33
|
+
$ pbf example.proto > example.js
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Then read and write objects using the module like this:
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
var Pbf = require('pbf');
|
|
40
|
+
var Example = require('./example.js').Example;
|
|
41
|
+
|
|
42
|
+
// read
|
|
43
|
+
var pbf = new Pbf(buffer);
|
|
44
|
+
var obj = Example.read(pbf);
|
|
45
|
+
|
|
46
|
+
// write
|
|
47
|
+
var pbf = new Pbf();
|
|
48
|
+
Example.write(obj, pbf);
|
|
49
|
+
var buffer = pbf.finish();
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Alternatively, you can compile a module directly in the code:
|
|
53
|
+
|
|
54
|
+
```js
|
|
55
|
+
var compile = require('pbf/compile');
|
|
56
|
+
var schema = require('protocol-buffers-schema');
|
|
57
|
+
|
|
58
|
+
var proto = schema.parse(fs.readFileSync('example.proto'));
|
|
59
|
+
var Test = compile(proto).Test;
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
If you use `webpack` as your module bundler, you can use [pbf-loader](https://github.com/trivago/pbf-loader)
|
|
63
|
+
to load .proto files directly. It returns a compiled module ready to be used.
|
|
64
|
+
|
|
65
|
+
Given you already configured your `webpack.config.js`, the code above would look like:
|
|
66
|
+
```js
|
|
67
|
+
var Pbf = require('pbf');
|
|
68
|
+
var proto = require('./example.proto');
|
|
69
|
+
|
|
70
|
+
var Test = proto.Test;
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
#### Custom Reading
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
var data = new Pbf(buffer).readFields(readData, {});
|
|
77
|
+
|
|
78
|
+
function readData(tag, data, pbf) {
|
|
79
|
+
if (tag === 1) data.name = pbf.readString();
|
|
80
|
+
else if (tag === 2) data.version = pbf.readVarint();
|
|
81
|
+
else if (tag === 3) data.layer = pbf.readMessage(readLayer, {});
|
|
82
|
+
}
|
|
83
|
+
function readLayer(tag, layer, pbf) {
|
|
84
|
+
if (tag === 1) layer.name = pbf.readString();
|
|
85
|
+
else if (tag === 3) layer.size = pbf.readVarint();
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
#### Custom Writing
|
|
90
|
+
|
|
91
|
+
```js
|
|
92
|
+
var pbf = new Pbf();
|
|
93
|
+
writeData(data, pbf);
|
|
94
|
+
var buffer = pbf.finish();
|
|
95
|
+
|
|
96
|
+
function writeData(data, pbf) {
|
|
97
|
+
pbf.writeStringField(1, data.name);
|
|
98
|
+
pbf.writeVarintField(2, data.version);
|
|
99
|
+
pbf.writeMessage(3, writeLayer, data.layer);
|
|
100
|
+
}
|
|
101
|
+
function writeLayer(layer, pbf) {
|
|
102
|
+
pbf.writeStringField(1, layer.name);
|
|
103
|
+
pbf.writeVarintField(2, layer.size);
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Install
|
|
108
|
+
|
|
109
|
+
Node and Browserify:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
npm install pbf
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Making a browser build:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
npm install
|
|
119
|
+
npm run build-dev # dist/pbf-dev.js (development build)
|
|
120
|
+
npm run build-min # dist/pbf.js (minified production build)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
CDN link: https://unpkg.com/pbf@3.0.5/dist/pbf.js
|
|
124
|
+
|
|
125
|
+
## API
|
|
126
|
+
|
|
127
|
+
Create a `Pbf` object, optionally given a `Buffer` or `Uint8Array` as input data:
|
|
128
|
+
|
|
129
|
+
```js
|
|
130
|
+
// parse a pbf file from disk in Node
|
|
131
|
+
var pbf = new Pbf(fs.readFileSync('data.pbf'));
|
|
132
|
+
|
|
133
|
+
// parse a pbf file in a browser after an ajax request with responseType="arraybuffer"
|
|
134
|
+
var pbf = new Pbf(new Uint8Array(xhr.response));
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
`Pbf` object properties:
|
|
138
|
+
|
|
139
|
+
```js
|
|
140
|
+
pbf.length; // length of the underlying buffer
|
|
141
|
+
pbf.pos; // current offset for reading or writing
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
#### Reading
|
|
145
|
+
|
|
146
|
+
Read a sequence of fields:
|
|
147
|
+
|
|
148
|
+
```js
|
|
149
|
+
pbf.readFields(function (tag) {
|
|
150
|
+
if (tag === 1) pbf.readVarint();
|
|
151
|
+
else if (tag === 2) pbf.readString();
|
|
152
|
+
else ...
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
It optionally accepts an object that will be passed to the reading function for easier construction of decoded data,
|
|
157
|
+
and also passes the `Pbf` object as a third argument:
|
|
158
|
+
|
|
159
|
+
```js
|
|
160
|
+
var result = pbf.readFields(callback, {})
|
|
161
|
+
|
|
162
|
+
function callback(tag, result, pbf) {
|
|
163
|
+
if (tag === 1) result.id = pbf.readVarint();
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
To read an embedded message, use `pbf.readMessage(fn[, obj])` (in the same way as `read`).
|
|
168
|
+
|
|
169
|
+
Read values:
|
|
170
|
+
|
|
171
|
+
```js
|
|
172
|
+
var value = pbf.readVarint();
|
|
173
|
+
var str = pbf.readString();
|
|
174
|
+
var numbers = pbf.readPackedVarint();
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
For lazy or partial decoding, simply save the position instead of reading a value,
|
|
178
|
+
then later set it back to the saved value and read:
|
|
179
|
+
|
|
180
|
+
```js
|
|
181
|
+
var fooPos = -1;
|
|
182
|
+
pbf.readFields(function (tag) {
|
|
183
|
+
if (tag === 1) fooPos = pbf.pos;
|
|
184
|
+
});
|
|
185
|
+
...
|
|
186
|
+
pbf.pos = fooPos;
|
|
187
|
+
pbf.readMessage(readFoo);
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Scalar reading methods:
|
|
191
|
+
|
|
192
|
+
* `readVarint(isSigned)` (pass `true` if you expect negative varints)
|
|
193
|
+
* `readSVarint()`
|
|
194
|
+
* `readFixed32()`
|
|
195
|
+
* `readFixed64()`
|
|
196
|
+
* `readSFixed32()`
|
|
197
|
+
* `readSFixed64()`
|
|
198
|
+
* `readBoolean()`
|
|
199
|
+
* `readFloat()`
|
|
200
|
+
* `readDouble()`
|
|
201
|
+
* `readString()`
|
|
202
|
+
* `readBytes()`
|
|
203
|
+
* `skip(value)`
|
|
204
|
+
|
|
205
|
+
Packed reading methods:
|
|
206
|
+
|
|
207
|
+
* `readPackedVarint(arr, isSigned)` (appends read items to `arr`)
|
|
208
|
+
* `readPackedSVarint(arr)`
|
|
209
|
+
* `readPackedFixed32(arr)`
|
|
210
|
+
* `readPackedFixed64(arr)`
|
|
211
|
+
* `readPackedSFixed32(arr)`
|
|
212
|
+
* `readPackedSFixed64(arr)`
|
|
213
|
+
* `readPackedBoolean(arr)`
|
|
214
|
+
* `readPackedFloat(arr)`
|
|
215
|
+
* `readPackedDouble(arr)`
|
|
216
|
+
|
|
217
|
+
#### Writing
|
|
218
|
+
|
|
219
|
+
Write values:
|
|
220
|
+
|
|
221
|
+
```js
|
|
222
|
+
pbf.writeVarint(123);
|
|
223
|
+
pbf.writeString("Hello world");
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Write an embedded message:
|
|
227
|
+
|
|
228
|
+
```js
|
|
229
|
+
pbf.writeMessage(1, writeObj, obj);
|
|
230
|
+
|
|
231
|
+
function writeObj(obj, pbf) {
|
|
232
|
+
pbf.writeStringField(obj.name);
|
|
233
|
+
pbf.writeVarintField(obj.version);
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Field writing methods:
|
|
238
|
+
|
|
239
|
+
* `writeVarintField(tag, val)`
|
|
240
|
+
* `writeSVarintField(tag, val)`
|
|
241
|
+
* `writeFixed32Field(tag, val)`
|
|
242
|
+
* `writeFixed64Field(tag, val)`
|
|
243
|
+
* `writeSFixed32Field(tag, val)`
|
|
244
|
+
* `writeSFixed64Field(tag, val)`
|
|
245
|
+
* `writeBooleanField(tag, val)`
|
|
246
|
+
* `writeFloatField(tag, val)`
|
|
247
|
+
* `writeDoubleField(tag, val)`
|
|
248
|
+
* `writeStringField(tag, val)`
|
|
249
|
+
* `writeBytesField(tag, buffer)`
|
|
250
|
+
|
|
251
|
+
Packed field writing methods:
|
|
252
|
+
|
|
253
|
+
* `writePackedVarint(tag, val)`
|
|
254
|
+
* `writePackedSVarint(tag, val)`
|
|
255
|
+
* `writePackedSFixed32(tag, val)`
|
|
256
|
+
* `writePackedSFixed64(tag, val)`
|
|
257
|
+
* `writePackedBoolean(tag, val)`
|
|
258
|
+
* `writePackedFloat(tag, val)`
|
|
259
|
+
* `writePackedDouble(tag, val)`
|
|
260
|
+
|
|
261
|
+
Scalar writing methods:
|
|
262
|
+
|
|
263
|
+
* `writeVarint(val)`
|
|
264
|
+
* `writeSVarint(val)`
|
|
265
|
+
* `writeSFixed32(val)`
|
|
266
|
+
* `writeSFixed64(val)`
|
|
267
|
+
* `writeBoolean(val)`
|
|
268
|
+
* `writeFloat(val)`
|
|
269
|
+
* `writeDouble(val)`
|
|
270
|
+
* `writeString(val)`
|
|
271
|
+
* `writeBytes(buffer)`
|
|
272
|
+
|
|
273
|
+
Message writing methods:
|
|
274
|
+
|
|
275
|
+
* `writeMessage(tag, fn[, obj])`
|
|
276
|
+
* `writeRawMessage(fn[, obj])`
|
|
277
|
+
|
|
278
|
+
Misc methods:
|
|
279
|
+
|
|
280
|
+
* `realloc(minBytes)` - pad the underlying buffer size to accommodate the given number of bytes;
|
|
281
|
+
note that the size increases exponentially, so it won't necessarily equal the size of data written
|
|
282
|
+
* `finish()` - make the current buffer ready for reading and return the data as a buffer slice
|
|
283
|
+
* `destroy()` - dispose the buffer
|
|
284
|
+
|
|
285
|
+
For an example of a real-world usage of the library, see [vector-tile-js](https://github.com/mapbox/vector-tile-js).
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
## Proto Schema to JavaScript
|
|
289
|
+
|
|
290
|
+
If installed globally, `pbf` provides a binary that compiles `proto` files into JavaScript modules. Usage:
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
$ pbf <proto_path> [--no-write] [--no-read] [--browser]
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
The `--no-write` and `--no-read` switches remove corresponding code in the output.
|
|
297
|
+
The `--browser` switch makes the module work in browsers instead of Node.
|
|
298
|
+
|
|
299
|
+
The resulting module exports each message by name with the following methods:
|
|
300
|
+
|
|
301
|
+
* `read(pbf)` - decodes an object from the given `Pbf` instance
|
|
302
|
+
* `write(obj, pbf)` - encodes an object into the given `Pbf` instance (usually empty)
|
|
303
|
+
|
|
304
|
+
The resulting code is clean and simple, so feel free to customize it.
|
|
305
|
+
|
|
306
|
+
[pbf]: https://npmjs.org/package/pbf
|
|
307
|
+
|
|
308
|
+
[npm-image]: https://img.shields.io/npm/v/@mapwhit/pbf
|
|
309
|
+
[npm-url]: https://npmjs.org/package/@mapwhit/pbf
|
|
310
|
+
|
|
311
|
+
[build-url]: https://github.com/mapwhit/pbf/actions/workflows/check.yaml
|
|
312
|
+
[build-image]: https://img.shields.io/github/workflow/status/mapwhit/pbf/check
|
|
313
|
+
|
|
314
|
+
[deps-image]: https://img.shields.io/librariesio/release/npm/@mapwhit/pbf
|
|
315
|
+
[deps-url]: https://libraries.io/npm/@mapwhit%2Fpbf
|
package/index.js
ADDED
|
@@ -0,0 +1,698 @@
|
|
|
1
|
+
const assert = require('assert');
|
|
2
|
+
const ieee754 = require('ieee754');
|
|
3
|
+
|
|
4
|
+
const SHIFT_LEFT_32 = (1 << 16) * (1 << 16);
|
|
5
|
+
const SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32;
|
|
6
|
+
|
|
7
|
+
// Threshold chosen based on both benchmarking and knowledge about browser string
|
|
8
|
+
// data structures (which currently switch structure types at 12 bytes or more)
|
|
9
|
+
const TEXT_DECODER_MIN_LENGTH = 12;
|
|
10
|
+
const utf8TextDecoder = typeof TextDecoder === 'undefined' ? null : new TextDecoder('utf-8');
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Pbf {
|
|
14
|
+
constructor(buf) {
|
|
15
|
+
this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0);
|
|
16
|
+
this.pos = 0;
|
|
17
|
+
this.type = 0;
|
|
18
|
+
this.length = this.buf.length;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
destroy() {
|
|
22
|
+
this.buf = null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// === READING =================================================================
|
|
26
|
+
|
|
27
|
+
readFields(readField, result, end = this.length) {
|
|
28
|
+
while (this.pos < end) {
|
|
29
|
+
const val = this.readVarint();
|
|
30
|
+
const tag = val >> 3;
|
|
31
|
+
const startPos = this.pos;
|
|
32
|
+
|
|
33
|
+
this.type = val & 0x7;
|
|
34
|
+
readField(tag, result, this);
|
|
35
|
+
|
|
36
|
+
if (this.pos === startPos) this.skip(val);
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
readMessage(readField, result) {
|
|
42
|
+
return this.readFields(readField, result, this.readVarint() + this.pos);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
readFixed32() {
|
|
46
|
+
const val = readUInt32(this.buf, this.pos);
|
|
47
|
+
this.pos += 4;
|
|
48
|
+
return val;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
readSFixed32() {
|
|
52
|
+
const val = readInt32(this.buf, this.pos);
|
|
53
|
+
this.pos += 4;
|
|
54
|
+
return val;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed)
|
|
58
|
+
|
|
59
|
+
readFixed64() {
|
|
60
|
+
const val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
|
|
61
|
+
this.pos += 8;
|
|
62
|
+
return val;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
readSFixed64() {
|
|
66
|
+
const val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
|
|
67
|
+
this.pos += 8;
|
|
68
|
+
return val;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
readFloat() {
|
|
72
|
+
const val = ieee754.read(this.buf, this.pos, true, 23, 4);
|
|
73
|
+
this.pos += 4;
|
|
74
|
+
return val;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
readDouble() {
|
|
78
|
+
const val = ieee754.read(this.buf, this.pos, true, 52, 8);
|
|
79
|
+
this.pos += 8;
|
|
80
|
+
return val;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
readVarint(isSigned) {
|
|
84
|
+
const buf = this.buf;
|
|
85
|
+
|
|
86
|
+
let b = buf[this.pos++];
|
|
87
|
+
let val = b & 0x7f;
|
|
88
|
+
if (b < 0x80) return val;
|
|
89
|
+
b = buf[this.pos++];
|
|
90
|
+
val |= (b & 0x7f) << 7;
|
|
91
|
+
if (b < 0x80) return val;
|
|
92
|
+
b = buf[this.pos++];
|
|
93
|
+
val |= (b & 0x7f) << 14;
|
|
94
|
+
if (b < 0x80) return val;
|
|
95
|
+
b = buf[this.pos++];
|
|
96
|
+
val |= (b & 0x7f) << 21;
|
|
97
|
+
if (b < 0x80) return val;
|
|
98
|
+
b = buf[this.pos];
|
|
99
|
+
val |= (b & 0x0f) << 28;
|
|
100
|
+
|
|
101
|
+
return readVarintRemainder(val, isSigned, this);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
readVarint64() { // for compatibility with v2.0.1
|
|
105
|
+
return this.readVarint(true);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
readSVarint() {
|
|
109
|
+
const num = this.readVarint();
|
|
110
|
+
return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
readBoolean() {
|
|
114
|
+
return Boolean(this.readVarint());
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
readString() {
|
|
118
|
+
const end = this.readVarint() + this.pos;
|
|
119
|
+
const pos = this.pos;
|
|
120
|
+
this.pos = end;
|
|
121
|
+
|
|
122
|
+
if (end - pos >= TEXT_DECODER_MIN_LENGTH && utf8TextDecoder) {
|
|
123
|
+
// longer strings are fast with the built-in browser TextDecoder API
|
|
124
|
+
return readUtf8TextDecoder(this.buf, pos, end);
|
|
125
|
+
}
|
|
126
|
+
// short strings are fast with our custom implementation
|
|
127
|
+
return readUtf8(this.buf, pos, end);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
readBytes() {
|
|
131
|
+
const end = this.readVarint() + this.pos;
|
|
132
|
+
const buffer = this.buf.subarray(this.pos, end);
|
|
133
|
+
this.pos = end;
|
|
134
|
+
return buffer;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// verbose for performance reasons; doesn't affect gzipped size
|
|
138
|
+
|
|
139
|
+
readPackedVarint(arr = [], isSigned = false) {
|
|
140
|
+
if (this.type !== Pbf.Bytes) return arr.push(this.readVarint(isSigned));
|
|
141
|
+
const end = readPackedEnd(this);
|
|
142
|
+
while (this.pos < end) arr.push(this.readVarint(isSigned));
|
|
143
|
+
return arr;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
readPackedSVarint(arr = []) {
|
|
147
|
+
if (this.type !== Pbf.Bytes) return arr.push(this.readSVarint());
|
|
148
|
+
const end = readPackedEnd(this);
|
|
149
|
+
while (this.pos < end) arr.push(this.readSVarint());
|
|
150
|
+
return arr;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
readPackedBoolean(arr = []) {
|
|
154
|
+
if (this.type !== Pbf.Bytes) return arr.push(this.readBoolean());
|
|
155
|
+
const end = readPackedEnd(this);
|
|
156
|
+
while (this.pos < end) arr.push(this.readBoolean());
|
|
157
|
+
return arr;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
readPackedFloat(arr = []) {
|
|
161
|
+
if (this.type !== Pbf.Bytes) return arr.push(this.readFloat());
|
|
162
|
+
const end = readPackedEnd(this);
|
|
163
|
+
while (this.pos < end) arr.push(this.readFloat());
|
|
164
|
+
return arr;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
readPackedDouble(arr = []) {
|
|
168
|
+
if (this.type !== Pbf.Bytes) return arr.push(this.readDouble());
|
|
169
|
+
const end = readPackedEnd(this);
|
|
170
|
+
while (this.pos < end) arr.push(this.readDouble());
|
|
171
|
+
return arr;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
readPackedFixed32(arr = []) {
|
|
175
|
+
if (this.type !== Pbf.Bytes) return arr.push(this.readFixed32());
|
|
176
|
+
const end = readPackedEnd(this);
|
|
177
|
+
while (this.pos < end) arr.push(this.readFixed32());
|
|
178
|
+
return arr;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
readPackedSFixed32(arr = []) {
|
|
182
|
+
if (this.type !== Pbf.Bytes) return arr.push(this.readSFixed32());
|
|
183
|
+
const end = readPackedEnd(this);
|
|
184
|
+
while (this.pos < end) arr.push(this.readSFixed32());
|
|
185
|
+
return arr;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
readPackedFixed64(arr = []) {
|
|
189
|
+
if (this.type !== Pbf.Bytes) return arr.push(this.readFixed64());
|
|
190
|
+
const end = readPackedEnd(this);
|
|
191
|
+
while (this.pos < end) arr.push(this.readFixed64());
|
|
192
|
+
return arr;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
readPackedSFixed64(arr = []) {
|
|
196
|
+
if (this.type !== Pbf.Bytes) return arr.push(this.readSFixed64());
|
|
197
|
+
const end = readPackedEnd(this);
|
|
198
|
+
while (this.pos < end) arr.push(this.readSFixed64());
|
|
199
|
+
return arr;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
skip(val) {
|
|
203
|
+
const type = val & 0x7;
|
|
204
|
+
switch (type) {
|
|
205
|
+
case Pbf.Varint: while (this.buf[this.pos++] > 0x7f) { /* skip */ }
|
|
206
|
+
break;
|
|
207
|
+
case Pbf.Bytes: this.pos = this.readVarint() + this.pos;
|
|
208
|
+
break;
|
|
209
|
+
case Pbf.Fixed32: this.pos += 4;
|
|
210
|
+
break;
|
|
211
|
+
case Pbf.Fixed64: this.pos += 8;
|
|
212
|
+
break;
|
|
213
|
+
default: assert(false, `Unimplemented type: ${type}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// === WRITING =================================================================
|
|
218
|
+
|
|
219
|
+
writeTag(tag, type) {
|
|
220
|
+
this.writeVarint((tag << 3) | type);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
realloc(min) {
|
|
224
|
+
let length = this.length || 16;
|
|
225
|
+
|
|
226
|
+
while (length < this.pos + min) length *= 2;
|
|
227
|
+
|
|
228
|
+
if (length !== this.length) {
|
|
229
|
+
const buf = new Uint8Array(length);
|
|
230
|
+
buf.set(this.buf);
|
|
231
|
+
this.buf = buf;
|
|
232
|
+
this.length = length;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
finish() {
|
|
237
|
+
this.length = this.pos;
|
|
238
|
+
this.pos = 0;
|
|
239
|
+
return this.buf.subarray(0, this.length);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
writeFixed32(val) {
|
|
243
|
+
this.realloc(4);
|
|
244
|
+
writeInt32(this.buf, val, this.pos);
|
|
245
|
+
this.pos += 4;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
writeSFixed32(val) {
|
|
249
|
+
this.realloc(4);
|
|
250
|
+
writeInt32(this.buf, val, this.pos);
|
|
251
|
+
this.pos += 4;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
writeFixed64(val) {
|
|
255
|
+
this.realloc(8);
|
|
256
|
+
writeInt32(this.buf, val & -1, this.pos);
|
|
257
|
+
writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
|
|
258
|
+
this.pos += 8;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
writeSFixed64(val) {
|
|
262
|
+
this.realloc(8);
|
|
263
|
+
writeInt32(this.buf, val & -1, this.pos);
|
|
264
|
+
writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
|
|
265
|
+
this.pos += 8;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
writeVarint(val) {
|
|
269
|
+
val = +val || 0;
|
|
270
|
+
|
|
271
|
+
if (val > 0xfffffff || val < 0) {
|
|
272
|
+
writeBigVarint(val, this);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
this.realloc(4);
|
|
277
|
+
|
|
278
|
+
this.buf[this.pos++] = val & 0x7f | (val > 0x7f ? 0x80 : 0);
|
|
279
|
+
if (val <= 0x7f) return;
|
|
280
|
+
this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0);
|
|
281
|
+
if (val <= 0x7f) return;
|
|
282
|
+
this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0);
|
|
283
|
+
if (val <= 0x7f) return;
|
|
284
|
+
this.buf[this.pos++] = (val >>> 7) & 0x7f;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
writeSVarint(val) {
|
|
288
|
+
this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
writeBoolean(val) {
|
|
292
|
+
this.writeVarint(Boolean(val));
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
writeString(str) {
|
|
296
|
+
str = String(str);
|
|
297
|
+
this.realloc(str.length * 4);
|
|
298
|
+
|
|
299
|
+
this.pos++; // reserve 1 byte for short string length
|
|
300
|
+
|
|
301
|
+
const startPos = this.pos;
|
|
302
|
+
// write the string directly to the buffer and see how much was written
|
|
303
|
+
this.pos = writeUtf8(this.buf, str, this.pos);
|
|
304
|
+
const len = this.pos - startPos;
|
|
305
|
+
|
|
306
|
+
if (len >= 0x80) makeRoomForExtraLength(startPos, len, this);
|
|
307
|
+
|
|
308
|
+
// finally, write the message length in the reserved place and restore the position
|
|
309
|
+
this.pos = startPos - 1;
|
|
310
|
+
this.writeVarint(len);
|
|
311
|
+
this.pos += len;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
writeFloat(val) {
|
|
315
|
+
this.realloc(4);
|
|
316
|
+
ieee754.write(this.buf, val, this.pos, true, 23, 4);
|
|
317
|
+
this.pos += 4;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
writeDouble(val) {
|
|
321
|
+
this.realloc(8);
|
|
322
|
+
ieee754.write(this.buf, val, this.pos, true, 52, 8);
|
|
323
|
+
this.pos += 8;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
writeBytes(buffer) {
|
|
327
|
+
const len = buffer.length;
|
|
328
|
+
this.writeVarint(len);
|
|
329
|
+
this.realloc(len);
|
|
330
|
+
for (let i = 0; i < len; i++) this.buf[this.pos++] = buffer[i];
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
writeRawMessage(fn, obj) {
|
|
334
|
+
this.pos++; // reserve 1 byte for short message length
|
|
335
|
+
|
|
336
|
+
// write the message directly to the buffer and see how much was written
|
|
337
|
+
const startPos = this.pos;
|
|
338
|
+
fn(obj, this);
|
|
339
|
+
const len = this.pos - startPos;
|
|
340
|
+
|
|
341
|
+
if (len >= 0x80) makeRoomForExtraLength(startPos, len, this);
|
|
342
|
+
|
|
343
|
+
// finally, write the message length in the reserved place and restore the position
|
|
344
|
+
this.pos = startPos - 1;
|
|
345
|
+
this.writeVarint(len);
|
|
346
|
+
this.pos += len;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
writeMessage(tag, fn, obj) {
|
|
350
|
+
this.writeTag(tag, Pbf.Bytes);
|
|
351
|
+
this.writeRawMessage(fn, obj);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
writePackedVarint(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedVarint, arr); }
|
|
355
|
+
writePackedSVarint(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedSVarint, arr); }
|
|
356
|
+
writePackedBoolean(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedBoolean, arr); }
|
|
357
|
+
writePackedFloat(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedFloat, arr); }
|
|
358
|
+
writePackedDouble(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedDouble, arr); }
|
|
359
|
+
writePackedFixed32(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedFixed32, arr); }
|
|
360
|
+
writePackedSFixed32(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedSFixed32, arr); }
|
|
361
|
+
writePackedFixed64(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedFixed64, arr); }
|
|
362
|
+
writePackedSFixed64(tag, arr) { if (arr.length) this.writeMessage(tag, writePackedSFixed64, arr); }
|
|
363
|
+
|
|
364
|
+
writeBytesField(tag, buffer) {
|
|
365
|
+
this.writeTag(tag, Pbf.Bytes);
|
|
366
|
+
this.writeBytes(buffer);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
writeFixed32Field(tag, val) {
|
|
370
|
+
this.writeTag(tag, Pbf.Fixed32);
|
|
371
|
+
this.writeFixed32(val);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
writeSFixed32Field(tag, val) {
|
|
375
|
+
this.writeTag(tag, Pbf.Fixed32);
|
|
376
|
+
this.writeSFixed32(val);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
writeFixed64Field(tag, val) {
|
|
380
|
+
this.writeTag(tag, Pbf.Fixed64);
|
|
381
|
+
this.writeFixed64(val);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
writeSFixed64Field(tag, val) {
|
|
385
|
+
this.writeTag(tag, Pbf.Fixed64);
|
|
386
|
+
this.writeSFixed64(val);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
writeVarintField(tag, val) {
|
|
390
|
+
this.writeTag(tag, Pbf.Varint);
|
|
391
|
+
this.writeVarint(val);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
writeSVarintField(tag, val) {
|
|
395
|
+
this.writeTag(tag, Pbf.Varint);
|
|
396
|
+
this.writeSVarint(val);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
writeStringField(tag, str) {
|
|
400
|
+
this.writeTag(tag, Pbf.Bytes);
|
|
401
|
+
this.writeString(str);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
writeFloatField(tag, val) {
|
|
405
|
+
this.writeTag(tag, Pbf.Fixed32);
|
|
406
|
+
this.writeFloat(val);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
writeDoubleField(tag, val) {
|
|
410
|
+
this.writeTag(tag, Pbf.Fixed64);
|
|
411
|
+
this.writeDouble(val);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
writeBooleanField(tag, val) {
|
|
415
|
+
this.writeVarintField(tag, Boolean(val));
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum
|
|
420
|
+
Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64
|
|
421
|
+
Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields
|
|
422
|
+
Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32
|
|
423
|
+
|
|
424
|
+
module.exports = Pbf;
|
|
425
|
+
|
|
426
|
+
function readVarintRemainder(l, s, p) {
|
|
427
|
+
const { buf } = p;
|
|
428
|
+
|
|
429
|
+
let b = buf[p.pos++];
|
|
430
|
+
let h = (b & 0x70) >> 4;
|
|
431
|
+
if (b < 0x80) return toNum(l, h, s);
|
|
432
|
+
b = buf[p.pos++];
|
|
433
|
+
h |= (b & 0x7f) << 3;
|
|
434
|
+
if (b < 0x80) return toNum(l, h, s);
|
|
435
|
+
b = buf[p.pos++];
|
|
436
|
+
h |= (b & 0x7f) << 10;
|
|
437
|
+
if (b < 0x80) return toNum(l, h, s);
|
|
438
|
+
b = buf[p.pos++];
|
|
439
|
+
h |= (b & 0x7f) << 17;
|
|
440
|
+
if (b < 0x80) return toNum(l, h, s);
|
|
441
|
+
b = buf[p.pos++];
|
|
442
|
+
h |= (b & 0x7f) << 24;
|
|
443
|
+
if (b < 0x80) return toNum(l, h, s);
|
|
444
|
+
b = buf[p.pos++];
|
|
445
|
+
h |= (b & 0x01) << 31;
|
|
446
|
+
if (b < 0x80) return toNum(l, h, s);
|
|
447
|
+
|
|
448
|
+
assert(false, 'Expected varint not more than 10 bytes');
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
function readPackedEnd(pbf) {
|
|
452
|
+
return pbf.type === Pbf.Bytes ?
|
|
453
|
+
pbf.readVarint() + pbf.pos : pbf.pos + 1;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function toNum(low, high, isSigned) {
|
|
457
|
+
if (isSigned) {
|
|
458
|
+
return high * 0x100000000 + (low >>> 0);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
return ((high >>> 0) * 0x100000000) + (low >>> 0);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function writeBigVarint(val, pbf) {
|
|
465
|
+
|
|
466
|
+
assert(
|
|
467
|
+
val < 0x10000000000000000 && val >= -0x10000000000000000,
|
|
468
|
+
'Given varint doesn\'t fit into 10 bytes'
|
|
469
|
+
);
|
|
470
|
+
|
|
471
|
+
let low;
|
|
472
|
+
let high;
|
|
473
|
+
|
|
474
|
+
if (val >= 0) {
|
|
475
|
+
low = (val % 0x100000000) | 0;
|
|
476
|
+
high = (val / 0x100000000) | 0;
|
|
477
|
+
} else {
|
|
478
|
+
low = ~(-val % 0x100000000);
|
|
479
|
+
high = ~(-val / 0x100000000);
|
|
480
|
+
|
|
481
|
+
if (low ^ 0xffffffff) {
|
|
482
|
+
low = (low + 1) | 0;
|
|
483
|
+
} else {
|
|
484
|
+
low = 0;
|
|
485
|
+
high = (high + 1) | 0;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
pbf.realloc(10);
|
|
490
|
+
|
|
491
|
+
writeBigVarintLow(low, high, pbf);
|
|
492
|
+
writeBigVarintHigh(high, pbf);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function writeBigVarintLow(low, high, pbf) {
|
|
496
|
+
pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
|
|
497
|
+
low >>>= 7;
|
|
498
|
+
pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
|
|
499
|
+
low >>>= 7;
|
|
500
|
+
pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
|
|
501
|
+
low >>>= 7;
|
|
502
|
+
pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
|
|
503
|
+
low >>>= 7;
|
|
504
|
+
pbf.buf[pbf.pos] = low & 0x7f;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function writeBigVarintHigh(high, pbf) {
|
|
508
|
+
const lsb = (high & 0x07) << 4;
|
|
509
|
+
|
|
510
|
+
pbf.buf[pbf.pos++] |= lsb | (((high >>>= 3)) ? 0x80 : 0);
|
|
511
|
+
if (!high) return;
|
|
512
|
+
pbf.buf[pbf.pos++] = high & 0x7f | (((high >>>= 7)) ? 0x80 : 0);
|
|
513
|
+
if (!high) return;
|
|
514
|
+
pbf.buf[pbf.pos++] = high & 0x7f | (((high >>>= 7)) ? 0x80 : 0);
|
|
515
|
+
if (!high) return;
|
|
516
|
+
pbf.buf[pbf.pos++] = high & 0x7f | (((high >>>= 7)) ? 0x80 : 0);
|
|
517
|
+
if (!high) return;
|
|
518
|
+
pbf.buf[pbf.pos++] = high & 0x7f | (((high >>>= 7)) ? 0x80 : 0);
|
|
519
|
+
if (!high) return;
|
|
520
|
+
pbf.buf[pbf.pos++] = high & 0x7f;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
function makeRoomForExtraLength(startPos, len, pbf) {
|
|
524
|
+
const extraLen =
|
|
525
|
+
len <= 0x3fff ? 1 :
|
|
526
|
+
len <= 0x1fffff ? 2 :
|
|
527
|
+
len <= 0xfffffff ? 3 : Math.floor(Math.log(len) / (Math.LN2 * 7));
|
|
528
|
+
|
|
529
|
+
// if 1 byte isn't enough for encoding message length, shift the data to the right
|
|
530
|
+
pbf.realloc(extraLen);
|
|
531
|
+
for (let i = pbf.pos - 1; i >= startPos; i--) pbf.buf[i + extraLen] = pbf.buf[i];
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
function writePackedVarint(arr, pbf) { for (let i = 0; i < arr.length; i++) pbf.writeVarint(arr[i]); }
|
|
535
|
+
|
|
536
|
+
function writePackedSVarint(arr, pbf) { for (let i = 0; i < arr.length; i++) pbf.writeSVarint(arr[i]); }
|
|
537
|
+
|
|
538
|
+
function writePackedFloat(arr, pbf) { for (let i = 0; i < arr.length; i++) pbf.writeFloat(arr[i]); }
|
|
539
|
+
|
|
540
|
+
function writePackedDouble(arr, pbf) { for (let i = 0; i < arr.length; i++) pbf.writeDouble(arr[i]); }
|
|
541
|
+
|
|
542
|
+
function writePackedBoolean(arr, pbf) { for (let i = 0; i < arr.length; i++) pbf.writeBoolean(arr[i]); }
|
|
543
|
+
|
|
544
|
+
function writePackedFixed32(arr, pbf) { for (let i = 0; i < arr.length; i++) pbf.writeFixed32(arr[i]); }
|
|
545
|
+
|
|
546
|
+
function writePackedSFixed32(arr, pbf) { for (let i = 0; i < arr.length; i++) pbf.writeSFixed32(arr[i]); }
|
|
547
|
+
|
|
548
|
+
function writePackedFixed64(arr, pbf) { for (let i = 0; i < arr.length; i++) pbf.writeFixed64(arr[i]); }
|
|
549
|
+
|
|
550
|
+
function writePackedSFixed64(arr, pbf) { for (let i = 0; i < arr.length; i++) pbf.writeSFixed64(arr[i]); }
|
|
551
|
+
|
|
552
|
+
// Buffer code below from https://github.com/feross/buffer, MIT-licensed
|
|
553
|
+
|
|
554
|
+
function readUInt32(buf, pos) {
|
|
555
|
+
return ((buf[pos]) |
|
|
556
|
+
(buf[pos + 1] << 8) |
|
|
557
|
+
(buf[pos + 2] << 16)) +
|
|
558
|
+
(buf[pos + 3] * 0x1000000);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
function writeInt32(buf, val, pos) {
|
|
562
|
+
buf[pos] = val;
|
|
563
|
+
buf[pos + 1] = (val >>> 8);
|
|
564
|
+
buf[pos + 2] = (val >>> 16);
|
|
565
|
+
buf[pos + 3] = (val >>> 24);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
function readInt32(buf, pos) {
|
|
569
|
+
return ((buf[pos]) |
|
|
570
|
+
(buf[pos + 1] << 8) |
|
|
571
|
+
(buf[pos + 2] << 16)) +
|
|
572
|
+
(buf[pos + 3] << 24);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
function readUtf8(buf, pos, end) {
|
|
576
|
+
let str = '';
|
|
577
|
+
let i = pos;
|
|
578
|
+
|
|
579
|
+
while (i < end) {
|
|
580
|
+
const b0 = buf[i];
|
|
581
|
+
let c = null; // codepoint
|
|
582
|
+
let bytesPerSequence =
|
|
583
|
+
b0 > 0xEF ? 4 :
|
|
584
|
+
b0 > 0xDF ? 3 :
|
|
585
|
+
b0 > 0xBF ? 2 : 1;
|
|
586
|
+
|
|
587
|
+
if (i + bytesPerSequence > end) break;
|
|
588
|
+
|
|
589
|
+
let b1;
|
|
590
|
+
let b2;
|
|
591
|
+
let b3;
|
|
592
|
+
|
|
593
|
+
if (bytesPerSequence === 1) {
|
|
594
|
+
if (b0 < 0x80) {
|
|
595
|
+
c = b0;
|
|
596
|
+
}
|
|
597
|
+
} else if (bytesPerSequence === 2) {
|
|
598
|
+
b1 = buf[i + 1];
|
|
599
|
+
if ((b1 & 0xC0) === 0x80) {
|
|
600
|
+
c = (b0 & 0x1F) << 0x6 | (b1 & 0x3F);
|
|
601
|
+
if (c <= 0x7F) {
|
|
602
|
+
c = null;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
} else if (bytesPerSequence === 3) {
|
|
606
|
+
b1 = buf[i + 1];
|
|
607
|
+
b2 = buf[i + 2];
|
|
608
|
+
if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80) {
|
|
609
|
+
c = (b0 & 0xF) << 0xC | (b1 & 0x3F) << 0x6 | (b2 & 0x3F);
|
|
610
|
+
if (c <= 0x7FF || (c >= 0xD800 && c <= 0xDFFF)) {
|
|
611
|
+
c = null;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
} else if (bytesPerSequence === 4) {
|
|
615
|
+
b1 = buf[i + 1];
|
|
616
|
+
b2 = buf[i + 2];
|
|
617
|
+
b3 = buf[i + 3];
|
|
618
|
+
if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) {
|
|
619
|
+
c = (b0 & 0xF) << 0x12 | (b1 & 0x3F) << 0xC | (b2 & 0x3F) << 0x6 | (b3 & 0x3F);
|
|
620
|
+
if (c <= 0xFFFF || c >= 0x110000) {
|
|
621
|
+
c = null;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
if (c === null) {
|
|
627
|
+
c = 0xFFFD;
|
|
628
|
+
bytesPerSequence = 1;
|
|
629
|
+
|
|
630
|
+
} else if (c > 0xFFFF) {
|
|
631
|
+
c -= 0x10000;
|
|
632
|
+
str += String.fromCharCode(c >>> 10 & 0x3FF | 0xD800);
|
|
633
|
+
c = 0xDC00 | c & 0x3FF;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
str += String.fromCharCode(c);
|
|
637
|
+
i += bytesPerSequence;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
return str;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
function readUtf8TextDecoder(buf, pos, end) {
|
|
644
|
+
return utf8TextDecoder.decode(buf.subarray(pos, end));
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
function writeUtf8(buf, str, pos) {
|
|
648
|
+
for (let i = 0, c, lead; i < str.length; i++) {
|
|
649
|
+
c = str.charCodeAt(i); // code point
|
|
650
|
+
|
|
651
|
+
if (c > 0xD7FF && c < 0xE000) {
|
|
652
|
+
if (lead) {
|
|
653
|
+
if (c < 0xDC00) {
|
|
654
|
+
buf[pos++] = 0xEF;
|
|
655
|
+
buf[pos++] = 0xBF;
|
|
656
|
+
buf[pos++] = 0xBD;
|
|
657
|
+
lead = c;
|
|
658
|
+
continue;
|
|
659
|
+
} else {
|
|
660
|
+
c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000;
|
|
661
|
+
lead = null;
|
|
662
|
+
}
|
|
663
|
+
} else {
|
|
664
|
+
if (c > 0xDBFF || (i + 1 === str.length)) {
|
|
665
|
+
buf[pos++] = 0xEF;
|
|
666
|
+
buf[pos++] = 0xBF;
|
|
667
|
+
buf[pos++] = 0xBD;
|
|
668
|
+
} else {
|
|
669
|
+
lead = c;
|
|
670
|
+
}
|
|
671
|
+
continue;
|
|
672
|
+
}
|
|
673
|
+
} else if (lead) {
|
|
674
|
+
buf[pos++] = 0xEF;
|
|
675
|
+
buf[pos++] = 0xBF;
|
|
676
|
+
buf[pos++] = 0xBD;
|
|
677
|
+
lead = null;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
if (c < 0x80) {
|
|
681
|
+
buf[pos++] = c;
|
|
682
|
+
} else {
|
|
683
|
+
if (c < 0x800) {
|
|
684
|
+
buf[pos++] = c >> 0x6 | 0xC0;
|
|
685
|
+
} else {
|
|
686
|
+
if (c < 0x10000) {
|
|
687
|
+
buf[pos++] = c >> 0xC | 0xE0;
|
|
688
|
+
} else {
|
|
689
|
+
buf[pos++] = c >> 0x12 | 0xF0;
|
|
690
|
+
buf[pos++] = c >> 0xC & 0x3F | 0x80;
|
|
691
|
+
}
|
|
692
|
+
buf[pos++] = c >> 0x6 & 0x3F | 0x80;
|
|
693
|
+
}
|
|
694
|
+
buf[pos++] = c & 0x3F | 0x80;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
return pos;
|
|
698
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mapwhit/pbf",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "a low-level, lightweight protocol buffers implementation in JavaScript",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "make check"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"index.js"
|
|
11
|
+
],
|
|
12
|
+
"repository": "mapwhit/pbf",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"protocol",
|
|
15
|
+
"buffer",
|
|
16
|
+
"pbf",
|
|
17
|
+
"protobuf",
|
|
18
|
+
"binary",
|
|
19
|
+
"format",
|
|
20
|
+
"serialization",
|
|
21
|
+
"encoder",
|
|
22
|
+
"decoder"
|
|
23
|
+
],
|
|
24
|
+
"author": "Konstantin Kaefer",
|
|
25
|
+
"license": "BSD-3-Clause",
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/mapbox/pbf/issues"
|
|
28
|
+
},
|
|
29
|
+
"homepage": "https://github.com/mapbox/pbf",
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@pirxpilot/nanoassert": "~1",
|
|
32
|
+
"ieee754": "^1.1.12"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"benchmark": "^2.1.4",
|
|
36
|
+
"eslint": "^8",
|
|
37
|
+
"protobufjs": "~6",
|
|
38
|
+
"protocol-buffers": "~5",
|
|
39
|
+
"tap": "~16",
|
|
40
|
+
"tile-stats-runner": "^1.0.0"
|
|
41
|
+
},
|
|
42
|
+
"browser": {
|
|
43
|
+
"assert": "@pirxpilot/nanoassert"
|
|
44
|
+
}
|
|
45
|
+
}
|