@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.
Files changed (4) hide show
  1. package/LICENSE +27 -0
  2. package/README.md +315 -0
  3. package/index.js +698 -0
  4. 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
+ }