1 | # pbf
|
2 |
|
3 | [![build status](https://secure.travis-ci.org/mapbox/pbf.png)](http://travis-ci.org/mapbox/pbf) [![Coverage Status](https://coveralls.io/repos/mapbox/pbf/badge.png)](https://coveralls.io/r/mapbox/pbf)
|
4 |
|
5 | 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).
|
6 |
|
7 | Designed to be a building block for writing customized decoders and encoders for a stable protobuf schema.
|
8 | If you need an all-purpose protobuf JS library that does most of the work for you,
|
9 | take a look at [protocol-buffers](https://github.com/mafintosh/protocol-buffers).
|
10 |
|
11 | ## Example
|
12 |
|
13 | #### Reading
|
14 |
|
15 | ```js
|
16 | var pbf = new Pbf(buffer),
|
17 | name, version, layerName;
|
18 |
|
19 | pbf.readFields(function(tag) {
|
20 | if (tag === 1) name = pbf.readString();
|
21 | else if (tag === 2) version = pbf.readVarint();
|
22 | else if (tag === 3) pbf.readMessage(function(tag) {
|
23 | if (tag === 1) layerName = pbf.readString();
|
24 | });
|
25 | });
|
26 | ```
|
27 |
|
28 | #### Writing
|
29 |
|
30 | ```js
|
31 | var pbf = new Pbf();
|
32 |
|
33 | pbf.writeStringField(1, 'Hello world');
|
34 | pbf.writeVarintField(2, 300);
|
35 |
|
36 | var layer = new Pbf();
|
37 | layer.writeStringField(1, 'foobar');
|
38 |
|
39 | pbf.writeMessage(3, layer);
|
40 |
|
41 | var buffer = pbf.finish();
|
42 | ```
|
43 |
|
44 | ## Install
|
45 |
|
46 | Node and Browserify:
|
47 |
|
48 | ```bash
|
49 | npm install pbf
|
50 | ```
|
51 |
|
52 | Making a browser build:
|
53 |
|
54 | ```bash
|
55 | npm install
|
56 | npm run build-dev # pbf-dev.js (development build)
|
57 | npm run build-min # pbf.js (minified production build)
|
58 | ```
|
59 |
|
60 | ## API
|
61 |
|
62 | Create a Protobuf object, optionally given a `Buffer` as input data (or `Uint8Array` in browsers):
|
63 |
|
64 | ```js
|
65 | var pbf = Protobuf(/*Buffer or Uint8Array*/ buf);
|
66 | ```
|
67 |
|
68 | Protobuf object properties:
|
69 |
|
70 | ```js
|
71 | pbf.length; // length of the underlying buffer
|
72 | pbf.pos; // current offset for reading or writing
|
73 | ```
|
74 |
|
75 | #### Reading
|
76 |
|
77 | Read a sequence of fields:
|
78 |
|
79 | ```js
|
80 | pbf.readFields(function (tag) {
|
81 | if (tag === 1) pbf.readVarint();
|
82 | else if (tag === 2) pbf.readString();
|
83 | else ...
|
84 | });
|
85 | ```
|
86 |
|
87 | It optionally accepts an object that will be passed to the reading function for easier construction of decoded data,
|
88 | and also passes the Protobuf object as a third argument:
|
89 |
|
90 | ```js
|
91 | var result = pbf.readFields(callback, {})
|
92 |
|
93 | function callback(tag, result, pbf) {
|
94 | if (tag === 1) result.id = pbf.readVarint();
|
95 | }
|
96 | ```
|
97 |
|
98 | To read an embedded message, use `pbf.readMessage(fn[, obj])` (in the same way as `read`).
|
99 |
|
100 | Read values:
|
101 |
|
102 | ```js
|
103 | var value = pbf.readVarint();
|
104 | var packed = pbf.readPacked('UInt32');
|
105 | ```
|
106 |
|
107 | For lazy or partial decoding, simply save the position instead of reading a value,
|
108 | then later set it back to the saved value and read:
|
109 |
|
110 | ```js
|
111 | var fooPos = -1;
|
112 | pbf.readFields(function (tag) {
|
113 | if (tag === 1) fooPos = pbf.pos;
|
114 | });
|
115 | ...
|
116 | pbf.pos = fooPos;
|
117 | pbf.readMessage(readFoo);
|
118 | ```
|
119 |
|
120 | Basic reading methods:
|
121 |
|
122 | * `readVarint()`
|
123 | * `readSVarint()`
|
124 | * `readFixed32()`
|
125 | * `readFixed64()`
|
126 | * `readSFixed32()`
|
127 | * `readSFixed64()`
|
128 | * `readBoolean()`
|
129 | * `readFloat()`
|
130 | * `readDouble()`
|
131 | * `readString()`
|
132 | * `readBytes()`
|
133 | * `readPacked(type)`
|
134 | * `skip(value)`
|
135 |
|
136 | #### Writing
|
137 |
|
138 | Write values:
|
139 |
|
140 | ```js
|
141 | pbf.writeVarint(123);
|
142 | pbf.writeString("Hello world");
|
143 | ```
|
144 |
|
145 | Field writing methods:
|
146 |
|
147 | * `writeVarintField(tag, val)`
|
148 | * `writeSVarintField(tag, val)`
|
149 | * `writeFixed32Field(tag, val)`
|
150 | * `writeFixed64Field(tag, val)`
|
151 | * `writeSFixed32Field(tag, val)`
|
152 | * `writeSFixed64Field(tag, val)`
|
153 | * `writeBooleanField(tag, val)`
|
154 | * `writeFloatField(tag, val)`
|
155 | * `writeDoubleField(tag, val)`
|
156 | * `writeStringField(tag, val)`
|
157 | * `writeBytesField(tag, buffer)`
|
158 | * `writePacked(tag, type, items)`
|
159 | * `writeMessage(tag, pbf)`
|
160 |
|
161 | Scalar writing methods:
|
162 |
|
163 | * `writeVarint(val)`
|
164 | * `writeSVarint(val)`
|
165 | * `writeSFixed32(val)`
|
166 | * `writeSFixed64(val)`
|
167 | * `writeFloat(val)`
|
168 | * `writeDouble(val)`
|
169 | * `writeString(val)`
|
170 | * `writeBytes(buffer)`
|
171 |
|
172 | Misc methods:
|
173 |
|
174 | * `realloc(minBytes)` - pad the underlying buffer size to accommodate the given number of bytes;
|
175 | note that the size increases exponentially, so it won't necessarily equal the size of data written
|
176 | * `finish()` - make the current buffer ready for reading and return the data as a buffer slice
|
177 | * `destroy()` - dispose the buffer
|
178 |
|
179 | For an example of a real-world usage of the library, see [vector-tile-js](https://github.com/mapbox/vector-tile-js).
|
180 |
|
181 | ## Changelog
|
182 |
|
183 | #### 1.1.4 (Jan 2, 2015)
|
184 |
|
185 | - Significantly improved `readPacked` and `writePacked` performance (the tile reading benchmark is now 70% faster).
|
186 |
|
187 | #### 1.1.3 (Dec 26, 2014)
|
188 |
|
189 | Brings tons of improvements and fixes over the previous version (`0.0.2`).
|
190 | Basically makes the library complete.
|
191 |
|
192 | ##### Improvements
|
193 |
|
194 | - Improved performance of both reading and writing.
|
195 | - Made the browser build 3 times smaller.
|
196 | - Added convenience `readFields` and `readMessage` methods for a much easier reading API.
|
197 | - Added reading methods: `readFloat`, `readBoolean`, `readSFixed32`, `readSFixed64`.
|
198 | - Added writing methods: `writeUInt64`, `writeSFixed32`, `writeSFixed64`.
|
199 | - Improved `readDouble` and `readString` to use native Buffer methods under Node.
|
200 | - Improved `readString` and `writeString` to use HTML5 `TextEncoder` and `TextDecoder` where available.
|
201 | - Made `Pbf` `buffer` argument optional.
|
202 | - Added extensive docs and examples in the readme.
|
203 | - Added an extensive test suite that brings test coverage up to 100%.
|
204 |
|
205 | ##### Breaking API changes
|
206 |
|
207 | - Renamed `readBuffer`/`writeBuffer` to `readBytes`/`writeBytes`.
|
208 | - Renamed `readUInt32`/`writeUInt32` to `readFixed32`/`writeFixed32`, etc.
|
209 | - Renamed `writeTaggedVarint` to `writeVarintField`, etc.
|
210 | - Changed `writePacked` signature from `(type, tag, items)` to `(tag, type, items)`.
|
211 |
|
212 | ##### Bugfixes
|
213 |
|
214 | - Fixed `readVarint` to handle varints bigger than 6 bytes.
|
215 | - Fixed `readSVarint` to handle number bigger than `2^30`.
|
216 | - Fixed `writeVarint` failing on some integers.
|
217 | - Fixed `writeVarint` not throwing an error on numbers that are too big.
|
218 | - Fixed `readUInt64` always failing.
|
219 | - Fixed writing to an empty buffer always failing.
|