Comparing version 0.0.2 to 1.0.0
509
index.js
'use strict'; | ||
var ieee754 = require('ieee754'); | ||
module.exports = Protobuf; | ||
module.exports = Protobuf; | ||
var Buffer = typeof window !== 'undefined' ? require('./buffer') : global.Buffer; | ||
function Protobuf(buf) { | ||
this.buf = buf; | ||
buf = buf || new Buffer(4); | ||
this.buf = buf instanceof Uint8Array ? Buffer.wrap(buf) : buf; | ||
this.pos = 0; | ||
this.length = buf.length; | ||
} | ||
Protobuf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum | ||
Protobuf.Fixed64 = 1; // double, fixed64, sfixed64 | ||
Protobuf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields | ||
Protobuf.Fixed32 = 5; // float, fixed32, sfixed32 | ||
var SHIFT_LEFT_32 = (1 << 16) * (1 << 16), | ||
SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32; | ||
Protobuf.prototype = { | ||
get length() { return this.buf.length; } | ||
}; | ||
Protobuf.Varint = 0; | ||
Protobuf.Int64 = 1; | ||
Protobuf.Message = 2; | ||
Protobuf.String = 2; | ||
Protobuf.Packed = 2; | ||
Protobuf.Int32 = 5; | ||
destroy: function() { | ||
this.buf = null; | ||
}, | ||
Protobuf.prototype.destroy = function() { | ||
this.buf = null; | ||
}; | ||
// === READING ================================================================= | ||
// === READING ================================================================= | ||
readFields: function(readField, end) { | ||
end = end || this.length; | ||
Protobuf.prototype.readUInt32 = function() { | ||
var val = this.buf.readUInt32LE(this.pos); | ||
this.pos += 4; | ||
return val; | ||
}; | ||
while (this.pos < end) { | ||
var val = this.readVarint(), | ||
tag = val >> 3, | ||
startPos = this.pos; | ||
readField(tag); | ||
if (this.pos === startPos) this.skip(val); | ||
} | ||
}, | ||
Protobuf.prototype.readUInt64 = function() { | ||
var val = this.buf.readUInt64LE(this.pos); | ||
this.pos += 8; | ||
return val; | ||
}; | ||
readMessage: function(readField) { | ||
var bytes = this.readVarint(); | ||
this.readFields(readField, this.pos + bytes); | ||
}, | ||
Protobuf.prototype.readDouble = function() { | ||
var val = ieee754.read(this.buf, this.pos, true, 52, 8); | ||
this.pos += 8; | ||
return val; | ||
}; | ||
readFixed32: function() { | ||
var val = this.buf.readUInt32LE(this.pos); | ||
this.pos += 4; | ||
return val; | ||
}, | ||
Protobuf.prototype.readVarint = function() { | ||
// TODO: bounds checking | ||
var pos = this.pos; | ||
if (this.buf[pos] <= 0x7f) { | ||
this.pos++; | ||
return this.buf[pos]; | ||
} else if (this.buf[pos + 1] <= 0x7f) { | ||
this.pos += 2; | ||
return (this.buf[pos] & 0x7f) | (this.buf[pos + 1] << 7); | ||
} else if (this.buf[pos + 2] <= 0x7f) { | ||
this.pos += 3; | ||
return (this.buf[pos] & 0x7f) | (this.buf[pos + 1] & 0x7f) << 7 | (this.buf[pos + 2]) << 14; | ||
} else if (this.buf[pos + 3] <= 0x7f) { | ||
readFixed64: function() { | ||
var val = this.buf.readUInt32LE(this.pos) + this.buf.readUInt32LE(this.pos + 4) * SHIFT_LEFT_32; | ||
this.pos += 8; | ||
return val; | ||
}, | ||
readFloat: function() { | ||
var val = this.buf.readFloatLE(this.pos); | ||
this.pos += 4; | ||
return (this.buf[pos] & 0x7f) | (this.buf[pos + 1] & 0x7f) << 7 | (this.buf[pos + 2] & 0x7f) << 14 | (this.buf[pos + 3]) << 21; | ||
} else if (this.buf[pos + 4] <= 0x7f) { | ||
this.pos += 5; | ||
return ((this.buf[pos] & 0x7f) | (this.buf[pos + 1] & 0x7f) << 7 | (this.buf[pos + 2] & 0x7f) << 14 | (this.buf[pos + 3]) << 21) + (this.buf[pos + 4] * 268435456); | ||
} else { | ||
this.skip(Protobuf.Varint); | ||
return 0; | ||
// throw new Error("TODO: Handle 6+ byte varints"); | ||
} | ||
}; | ||
return val; | ||
}, | ||
Protobuf.prototype.readSVarint = function() { | ||
var num = this.readVarint(); | ||
if (num > 2147483647) throw new Error('TODO: Handle numbers >= 2^30'); | ||
// zigzag encoding | ||
return ((num >> 1) ^ -(num & 1)); | ||
}; | ||
readDouble: function() { | ||
var val = this.buf.readDoubleLE(this.pos); | ||
this.pos += 8; | ||
return val; | ||
}, | ||
Protobuf.prototype.readString = function() { | ||
var bytes = this.readVarint(); | ||
// TODO: bounds checking | ||
var chr = String.fromCharCode; | ||
var b = this.buf; | ||
var p = this.pos; | ||
var end = this.pos + bytes; | ||
var str = ''; | ||
while (p < end) { | ||
if (b[p] <= 0x7F) str += chr(b[p++]); | ||
else if (b[p] <= 0xBF) throw new Error('Invalid UTF-8 codepoint: ' + b[p]); | ||
else if (b[p] <= 0xDF) str += chr((b[p++] & 0x1F) << 6 | (b[p++] & 0x3F)); | ||
else if (b[p] <= 0xEF) str += chr((b[p++] & 0x1F) << 12 | (b[p++] & 0x3F) << 6 | (b[p++] & 0x3F)); | ||
else if (b[p] <= 0xF7) p += 4; // We can't handle these codepoints in JS, so skip. | ||
else if (b[p] <= 0xFB) p += 5; | ||
else if (b[p] <= 0xFD) p += 6; | ||
else throw new Error('Invalid UTF-8 codepoint: ' + b[p]); | ||
} | ||
this.pos += bytes; | ||
return str; | ||
}; | ||
readVarint: function() { | ||
var buf = this.buf, | ||
val, b, b0, b1, b2, b3; | ||
Protobuf.prototype.readBuffer = function() { | ||
var bytes = this.readVarint(); | ||
var buffer = this.buf.subarray(this.pos, this.pos + bytes); | ||
this.pos += bytes; | ||
return buffer; | ||
}; | ||
b0 = buf[this.pos++]; if (b0 < 0x80) return b0; b0 = b0 & 0x7f; | ||
b1 = buf[this.pos++]; if (b1 < 0x80) return b0 | b1 << 7; b1 = (b1 & 0x7f) << 7; | ||
b2 = buf[this.pos++]; if (b2 < 0x80) return b0 | b1 | b2 << 14; b2 = (b2 & 0x7f) << 14; | ||
b3 = buf[this.pos++]; if (b3 < 0x80) return b0 | b1 | b2 | b3 << 21; | ||
Protobuf.prototype.readPacked = function(type) { | ||
// TODO: bounds checking | ||
var bytes = this.readVarint(); | ||
var end = this.pos + bytes; | ||
var array = []; | ||
while (this.pos < end) { | ||
array.push(this['read' + type]()); | ||
} | ||
return array; | ||
}; | ||
val = b0 | b1 | b2 | (b3 & 0x7f) << 21; | ||
Protobuf.prototype.skip = function(val) { | ||
// TODO: bounds checking | ||
var type = val & 0x7; | ||
switch (type) { | ||
/* varint */ case Protobuf.Varint: while (this.buf[this.pos++] > 0x7f); break; | ||
/* 64 bit */ case Protobuf.Int64: this.pos += 8; break; | ||
/* length */ case Protobuf.Message: var bytes = this.readVarint(); this.pos += bytes; break; | ||
/* 32 bit */ case Protobuf.Int32: this.pos += 4; break; | ||
default: throw new Error('Unimplemented type: ' + type); | ||
} | ||
}; | ||
b = buf[this.pos++]; val += (b & 0x7f) * 0x10000000; if (b < 0x80) return val; | ||
b = buf[this.pos++]; val += (b & 0x7f) * 0x800000000; if (b < 0x80) return val; | ||
b = buf[this.pos++]; val += (b & 0x7f) * 0x40000000000; if (b < 0x80) return val; | ||
b = buf[this.pos++]; val += (b & 0x7f) * 0x2000000000000; if (b < 0x80) return val; | ||
b = buf[this.pos++]; val += (b & 0x7f) * 0x100000000000000; if (b < 0x80) return val; | ||
b = buf[this.pos++]; val += (b & 0x7f) * 0x8000000000000000; if (b < 0x80) return val; | ||
// === WRITING ================================================================= | ||
throw new Error('Expected varint not more than 10 bytes'); | ||
}, | ||
Protobuf.prototype.writeTag = function(tag, type) { | ||
this.writeVarint((tag << 3) | type); | ||
}; | ||
readSVarint: function() { | ||
var num = this.readVarint(); | ||
return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding | ||
}, | ||
Protobuf.prototype.realloc = function(min) { | ||
var length = this.buf.length; | ||
while (length < this.pos + min) length *= 2; | ||
if (length != this.buf.length) { | ||
var buf = new Buffer(length); | ||
this.buf.copy(buf); | ||
this.buf = buf; | ||
} | ||
}; | ||
readBoolean: function() { | ||
return Boolean(this.readVarint()); | ||
}, | ||
Protobuf.prototype.finish = function() { | ||
return this.buf.slice(0, this.pos); | ||
}; | ||
readString: function() { | ||
var bytes = this.readVarint(), | ||
str = this.buf.toString('utf8', this.pos, this.pos + bytes); | ||
this.pos += bytes; | ||
return str; | ||
}, | ||
Protobuf.prototype.writePacked = function(type, tag, items) { | ||
if (!items.length) return; | ||
readBytes: function() { | ||
var bytes = this.readVarint(); | ||
var buffer = this.buf.slice(this.pos, this.pos + bytes); | ||
this.pos += bytes; | ||
return buffer; | ||
}, | ||
var message = new Protobuf(); | ||
for (var i = 0; i < items.length; i++) { | ||
message['write' + type](items[i]); | ||
} | ||
var data = message.finish(); | ||
readPacked: function(type) { | ||
var bytes = this.readVarint(); | ||
var end = this.pos + bytes; | ||
var array = []; | ||
var read = this['read' + type]; | ||
while (this.pos < end) { | ||
array.push(read.call(this)); | ||
} | ||
return array; | ||
}, | ||
this.writeTag(tag, Protobuf.Packed); | ||
this.writeBuffer(data); | ||
}; | ||
skip: function(val) { | ||
var type = val & 0x7; | ||
Protobuf.prototype.writeUInt32 = function(val) { | ||
this.realloc(4); | ||
this.buf.writeUInt32LE(val, this.pos); | ||
this.pos += 4; | ||
}; | ||
if (type === Protobuf.Varint) { | ||
var buf = this.buf; | ||
while (buf[this.pos++] > 0x7f); | ||
Protobuf.prototype.writeTaggedUInt32 = function(tag, val) { | ||
this.writeTag(tag, Protobuf.Int32); | ||
this.writeUInt32(val); | ||
}; | ||
} else if (type === Protobuf.Bytes) { | ||
var bytes = this.readVarint(); | ||
this.pos += bytes; | ||
Protobuf.prototype.writeVarint = function(val) { | ||
val = Number(val); | ||
if (isNaN(val)) { | ||
val = 0; | ||
} | ||
} else if (type === Protobuf.Fixed32) this.pos += 4; | ||
else if (type === Protobuf.Fixed64) this.pos += 8; | ||
else throw new Error('Unimplemented type: ' + type); | ||
}, | ||
if (val <= 0x7f) { | ||
this.realloc(1); | ||
this.buf[this.pos++] = val; | ||
} else if (val <= 0x3fff) { | ||
this.realloc(2); | ||
this.buf[this.pos++] = 0x80 | ((val >>> 0) & 0x7f); | ||
this.buf[this.pos++] = 0x00 | ((val >>> 7) & 0x7f); | ||
} else if (val <= 0x1ffffff) { | ||
this.realloc(3); | ||
this.buf[this.pos++] = 0x80 | ((val >>> 0) & 0x7f); | ||
this.buf[this.pos++] = 0x80 | ((val >>> 7) & 0x7f); | ||
this.buf[this.pos++] = 0x00 | ((val >>> 14) & 0x7f); | ||
} else if (val <= 0xfffffff) { | ||
// === WRITING ================================================================= | ||
writeTag: function(tag, type) { | ||
this.writeVarint((tag << 3) | type); | ||
}, | ||
realloc: function(min) { | ||
var length = this.length || 1; | ||
while (length < this.pos + min) length *= 2; | ||
if (length != this.length) { | ||
var buf = new Buffer(length); | ||
this.buf.copy(buf); | ||
this.buf = buf; | ||
this.length = length; | ||
} | ||
}, | ||
finish: function() { | ||
this.length = this.pos; | ||
this.pos = 0; | ||
return this.buf.slice(0, this.length); | ||
}, | ||
writePacked: function(type, tag, items) { | ||
if (!items.length) return; | ||
var message = new Protobuf(); | ||
var write = message['write' + type]; | ||
for (var i = 0; i < items.length; i++) { | ||
write.call(message, items[i]); | ||
} | ||
var data = message.finish(); | ||
this.writeTag(tag, Protobuf.Bytes); | ||
this.writeBytes(data); | ||
}, | ||
writeFixed32: function(val) { | ||
this.realloc(4); | ||
this.buf[this.pos++] = 0x80 | ((val >>> 0) & 0x7f); | ||
this.buf[this.pos++] = 0x80 | ((val >>> 7) & 0x7f); | ||
this.buf[this.pos++] = 0x80 | ((val >>> 14) & 0x7f); | ||
this.buf[this.pos++] = 0x00 | ((val >>> 21) & 0x7f); | ||
} else { | ||
while (val > 0) { | ||
var b = val & 0x7f; | ||
val = Math.floor(val / 128); | ||
if (val > 0) b |= 0x80 | ||
this.buf.writeUInt32LE(val, this.pos); | ||
this.pos += 4; | ||
}, | ||
writeFixed64: function(val) { | ||
this.realloc(8); | ||
this.buf.writeInt32LE(val & -1, this.pos); | ||
this.buf.writeUInt32LE(Math.floor(val * SHIFT_RIGHT_32), this.pos + 4); | ||
this.pos += 8; | ||
}, | ||
writeVarint: function(val) { | ||
val = +val; | ||
if (val <= 0x7f) { | ||
this.realloc(1); | ||
this.buf[this.pos++] = b; | ||
this.buf[this.pos++] = val; | ||
} else if (val <= 0x3fff) { | ||
this.realloc(2); | ||
this.buf[this.pos++] = 0x80 | ((val >>> 0) & 0x7f); | ||
this.buf[this.pos++] = 0x00 | ((val >>> 7) & 0x7f); | ||
} else if (val <= 0x1fffff) { | ||
this.realloc(3); | ||
this.buf[this.pos++] = 0x80 | ((val >>> 0) & 0x7f); | ||
this.buf[this.pos++] = 0x80 | ((val >>> 7) & 0x7f); | ||
this.buf[this.pos++] = 0x00 | ((val >>> 14) & 0x7f); | ||
} else if (val <= 0xfffffff) { | ||
this.realloc(4); | ||
this.buf[this.pos++] = 0x80 | ((val >>> 0) & 0x7f); | ||
this.buf[this.pos++] = 0x80 | ((val >>> 7) & 0x7f); | ||
this.buf[this.pos++] = 0x80 | ((val >>> 14) & 0x7f); | ||
this.buf[this.pos++] = 0x00 | ((val >>> 21) & 0x7f); | ||
} else { | ||
var pos = this.pos; | ||
while (val >= 0x80) { | ||
this.realloc(1); | ||
this.buf[this.pos++] = (val & 0xff) | 0x80; | ||
val /= 0x80; | ||
} | ||
this.realloc(1); | ||
this.buf[this.pos++] = val | 0; | ||
if (this.pos - pos > 10) throw new Error("Given varint doesn't fit into 10 bytes"); | ||
} | ||
} | ||
}; | ||
}, | ||
Protobuf.prototype.writeTaggedVarint = function(tag, val) { | ||
this.writeTag(tag, Protobuf.Varint); | ||
this.writeVarint(val); | ||
}; | ||
writeSVarint: function(val) { | ||
if (val >= 0) { | ||
this.writeVarint(val * 2); | ||
} else { | ||
this.writeVarint(val * -2 - 1); | ||
} | ||
}, | ||
Protobuf.prototype.writeSVarint = function(val) { | ||
if (val >= 0) { | ||
this.writeVarint(val * 2); | ||
} else { | ||
this.writeVarint(val * -2 - 1); | ||
} | ||
}; | ||
writeBoolean: function(val) { | ||
this.writeVarint(Boolean(val)); | ||
}, | ||
Protobuf.prototype.writeTaggedSVarint = function(tag, val) { | ||
this.writeTag(tag, Protobuf.Varint); | ||
this.writeSVarint(val); | ||
}; | ||
writeString: function(str) { | ||
str = String(str); | ||
var bytes = Buffer.byteLength(str); | ||
this.writeVarint(bytes); | ||
this.realloc(bytes); | ||
this.buf.write(str, this.pos); | ||
this.pos += bytes; | ||
}, | ||
Protobuf.prototype.writeBoolean = function(val) { | ||
this.writeVarint(Boolean(val)); | ||
}; | ||
writeFloat: function(val) { | ||
this.realloc(4); | ||
this.buf.writeFloatLE(val, this.pos); | ||
this.pos += 4; | ||
}, | ||
Protobuf.prototype.writeTaggedBoolean = function(tag, val) { | ||
this.writeTaggedVarint(tag, Boolean(val)); | ||
}; | ||
writeDouble: function(val) { | ||
this.realloc(8); | ||
this.buf.writeDoubleLE(val, this.pos); | ||
this.pos += 8; | ||
}, | ||
Protobuf.prototype.writeString = function(str) { | ||
str = String(str); | ||
var bytes = Buffer.byteLength(str); | ||
this.writeVarint(bytes); | ||
this.realloc(bytes); | ||
this.buf.write(str, this.pos); | ||
this.pos += bytes; | ||
}; | ||
writeBytes: function(buffer) { | ||
var len = buffer.length; | ||
this.writeVarint(len); | ||
this.realloc(len); | ||
for (var i = 0; i < len; i++) { | ||
this.buf[this.pos + i] = buffer[i]; | ||
} | ||
this.pos += len; | ||
}, | ||
Protobuf.prototype.writeTaggedString = function(tag, str) { | ||
this.writeTag(tag, Protobuf.String); | ||
this.writeString(str); | ||
}; | ||
writeBytesField: function(tag, buffer) { | ||
this.writeTag(tag, Protobuf.Bytes); | ||
this.writeBytes(buffer); | ||
}, | ||
Protobuf.prototype.writeFloat = function(val) { | ||
this.realloc(4); | ||
this.buf.writeFloatLE(val, this.pos); | ||
this.pos += 4; | ||
}; | ||
writeMessage: function(tag, protobuf) { | ||
var buffer = protobuf.finish(); | ||
this.writeTag(tag, Protobuf.Bytes); | ||
this.writeBytes(buffer); | ||
}, | ||
Protobuf.prototype.writeTaggedFloat = function(tag, val) { | ||
this.writeTag(tag, Protobuf.Int32); | ||
this.writeFloat(val); | ||
}; | ||
writeFixed32Field: function(tag, val) { | ||
this.writeTag(tag, Protobuf.Fixed32); | ||
this.writeFixed32(val); | ||
}, | ||
Protobuf.prototype.writeDouble = function(val) { | ||
this.realloc(8); | ||
this.buf.writeDoubleLE(val, this.pos); | ||
this.pos += 8; | ||
}; | ||
writeFixed64Field: function(tag, val) { | ||
this.writeTag(tag, Protobuf.Fixed64); | ||
this.writeFixed64(val); | ||
}, | ||
Protobuf.prototype.writeTaggedDouble = function(tag, val) { | ||
this.writeTag(tag, Protobuf.Int64); | ||
this.writeDouble(val); | ||
}; | ||
writeVarintField: function(tag, val) { | ||
this.writeTag(tag, Protobuf.Varint); | ||
this.writeVarint(val); | ||
}, | ||
Protobuf.prototype.writeBuffer = function(buffer) { | ||
var bytes = buffer.length; | ||
this.writeVarint(bytes); | ||
this.realloc(bytes); | ||
buffer.copy(this.buf, this.pos); | ||
this.pos += bytes; | ||
}; | ||
writeSVarintField: function(tag, val) { | ||
this.writeTag(tag, Protobuf.Varint); | ||
this.writeSVarint(val); | ||
}, | ||
Protobuf.prototype.writeTaggedBuffer = function(tag, buffer) { | ||
this.writeTag(tag, Protobuf.String); | ||
this.writeBuffer(buffer); | ||
}; | ||
writeStringField: function(tag, str) { | ||
this.writeTag(tag, Protobuf.Bytes); | ||
this.writeString(str); | ||
}, | ||
Protobuf.prototype.writeMessage = function(tag, protobuf) { | ||
var buffer = protobuf.finish(); | ||
this.writeTag(tag, Protobuf.Message); | ||
this.writeBuffer(buffer); | ||
writeFloatField: function(tag, val) { | ||
this.writeTag(tag, Protobuf.Fixed32); | ||
this.writeFloat(val); | ||
}, | ||
writeDoubleField: function(tag, val) { | ||
this.writeTag(tag, Protobuf.Fixed64); | ||
this.writeDouble(val); | ||
}, | ||
writeBooleanField: function(tag, val) { | ||
this.writeVarintField(tag, Boolean(val)); | ||
} | ||
}; |
{ | ||
"name": "pbf", | ||
"version": "0.0.2", | ||
"description": "a protocol buffer implementation in javascript", | ||
"version": "1.0.0", | ||
"description": "a low-level, lightweight protocol buffers implementation in JavaScript", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "tape test/index.js", | ||
"cov": "istanbul cover test/index.js && coveralls < ./coverage/lcov.info" | ||
"test": "jshint index.js test/*.js && tape test/index.js | faucet", | ||
"cov": "istanbul cover test/index.js && coveralls < ./coverage/lcov.info", | ||
"build-min": "browserify index.js -s Pbf | uglifyjs -c -m > pbf.js", | ||
"build-dev": "browserify index.js -d -s Pbf > pbf-dev.js" | ||
}, | ||
@@ -17,3 +19,5 @@ "repository": { | ||
"buffer", | ||
"pbf" | ||
"pbf", | ||
"protobuf", | ||
"binary" | ||
], | ||
@@ -29,8 +33,20 @@ "author": "Konstantin Kaefer", | ||
}, | ||
"jshintConfig": { | ||
"trailing": true, | ||
"undef": true, | ||
"unused": true, | ||
"indent": 4, | ||
"node": true | ||
}, | ||
"devDependencies": { | ||
"benchmark": "^1.0.0", | ||
"brfs": "1.0.1", | ||
"coveralls": "~2.10.1", | ||
"faucet": "0.0.1", | ||
"istanbul": "~0.2.11", | ||
"jshint": "^2.5.11", | ||
"tape": "~2.4.2", | ||
"istanbul": "~0.2.11", | ||
"brfs": "1.0.1", | ||
"coveralls": "~2.10.1" | ||
"uglify-js": "^2.4.16", | ||
"vector-tile": "^0.1.3" | ||
} | ||
} |
156
README.md
@@ -5,30 +5,146 @@ # pbf | ||
A [protocol buffers](http://code.google.com/p/protobuf/) implementation in | ||
JavaScript for node and browsers. | ||
A low-level, lightweight [protocol buffers](https://developers.google.com/protocol-buffers) implementation in JavaScript for Node and browsers. | ||
## install | ||
Designed to be a building block for writing a customized, lazy decoder for a stable protobuf schema. | ||
If you need an easy-to-use, all-purpose protobuf JS library that does most of the work for you, | ||
take a look at [protocol-buffers](https://github.com/mafintosh/protocol-buffers). | ||
npm install pbf | ||
## Install | ||
## api | ||
Node and Browserify: | ||
### `Protobuf(buf, pos)` | ||
```bash | ||
npm install pbf | ||
``` | ||
Making a browser build: | ||
```bash | ||
npm install | ||
npm run build-dev # pbf-dev.js (development build) | ||
npm run build-min # pbf.js (minified production build) | ||
``` | ||
## Example | ||
Reading: | ||
```js | ||
var Pbf = require('pbf'); | ||
var protobuffer = new Pbf(buffer); | ||
var varInt = protobuffer.readVarInt(); | ||
var pbf = new Pbf(buffer), | ||
name, version, layerName; | ||
pbf.readFields(function(tag) { | ||
if (tag === 1) name = pbf.readString(); | ||
else if (tag === 2) version = pbf.readVarint(); | ||
else if (tag === 3) { | ||
pbf.readMessage(function(tag) { | ||
if (tag === 1) layerName = pbf.readString(); | ||
}); | ||
} | ||
return result; | ||
}); | ||
``` | ||
Reading | ||
Writing: | ||
* readUInt32 | ||
* readUInt32LE | ||
* readUInt64 | ||
* readUInt64LE | ||
* readDouble | ||
* readDoubleLE | ||
* readVarint | ||
* readSVarint | ||
* readString | ||
* readPacked | ||
```js | ||
var pbf = new Pbf(); | ||
pbf.writeStringField(1, 'Hello world'); | ||
pbf.writeVarintField(2, 300); | ||
var layer = new Pbf(); | ||
layer.writeStringField(1, 'foobar'); | ||
pbf.writeMessage(3, layer); | ||
var buffer = pbf.finish(); | ||
``` | ||
## API | ||
Create a buffer: | ||
```js | ||
var pbf = Protobuf(/*Buffer*/ buf); | ||
``` | ||
Get buffer length: | ||
```js | ||
pbf.length; | ||
``` | ||
#### Reading | ||
Read a sequence of fields: | ||
```js | ||
pbf.readFields(function (tag) { | ||
if (tag === 1) pbf.readVarint(); | ||
else if (tag === 2) pbf.readString(); | ||
else ... | ||
}); | ||
``` | ||
To read an embedded message, use `pbf.readMessage(fn)` (in the same way as `read`). | ||
Read values: | ||
```js | ||
var value = pbf.readVarint(); | ||
var packed = pbf.readPacked('UInt32'); | ||
``` | ||
Basic reading methods: | ||
* `readVarint()` | ||
* `readSVarint()` | ||
* `readFixed32()` | ||
* `readFixed64()` | ||
* `readBoolean()` | ||
* `readFloat()` | ||
* `readDouble()` | ||
* `readString()` | ||
* `readBytes()` | ||
* `readPacked(type)` | ||
* `skip(value)` | ||
#### Writing | ||
Write values: | ||
```js | ||
pbf.writeVarint(123); | ||
pbf.writeString("Hello world"); | ||
``` | ||
Writing methods: | ||
* `writeVarintField(tag, val)` | ||
* `writeSVarintField(tag, val)` | ||
* `writeFixed32Field(tag, val)` | ||
* `writeFixed64Field(tag, val)` | ||
* `writeBooleanField(tag, val)` | ||
* `writeFloatField(tag, val)` | ||
* `writeDoubleField(tag, val)` | ||
* `writeStringField(tag, val)` | ||
* `writeBytesField(tag, buffer)` | ||
* `writePacked(type, tag, items)` | ||
* `writeVarint(val)` | ||
* `writeSVarint(val)` | ||
* `writeFixed32(val)` | ||
* `writeFixed64(val)` | ||
* `writeFloat(val)` | ||
* `writeDouble(val)` | ||
* `writeString(val)` | ||
* `writeBytes(buffer)` | ||
* `writeMessage(tag, pbf)` | ||
Misc methods: | ||
* `realloc(minBytes)` - pad the underlying buffer size to accommodate the given number of bytes | ||
* `finish()` - make the current buffer ready for reading and return the data as a buffer slice | ||
* `destroy()` - disposes the buffer | ||
For an example of a real-world usage of the library, see [vector-tile-js](https://github.com/mapbox/vector-tile-js). |
@@ -5,2 +5,12 @@ var Pbf = require('../'), | ||
require('./buffer.test'); | ||
function toArray(buf) { | ||
var arr = []; | ||
for (var i = 0; i < buf.length; i++) { | ||
arr.push(buf[i]); | ||
} | ||
return arr; | ||
} | ||
test('initialization', function(t) { | ||
@@ -12,22 +22,155 @@ var buf = new Pbf(new Buffer([])); | ||
test('readVarInt', function(t) { | ||
var buf = new Pbf(fs.readFileSync(__dirname + '/fixtures/3165.vector.pbf')); | ||
t.equal(buf.length, 28056); | ||
t.equal(buf.readVarint(), 120); | ||
t.equal(buf.readVarint(), 14876); | ||
t.equal(buf.readVarint(), 125); | ||
t.equal(buf.readVarint(), 9); | ||
buf.destroy(); | ||
test('realloc', function(t) { | ||
var buf = new Pbf(new Buffer([])); | ||
buf.realloc(5); | ||
t.equal(buf.length, 8); | ||
t.end(); | ||
}); | ||
var testNumbers = [1,0,0,4,14,23,40,86,141,113,925,258,1105,1291,6872,12545,65521,126522,133028,444205,846327,1883372, | ||
3716678,674158,15203102,27135056,42501689,110263473,6449928,65474499,943840723,1552431153,407193337,2193544970, | ||
8167778088,5502125480,14014009728,56371207648,9459068416,410595966336,673736830976,502662539776,2654996269056, | ||
5508583663616,6862782705664,34717688324096,1074895093760,95806297440256,130518477701120,197679237955584, | ||
301300890730496,1310140661760000,2883205519638528,2690669862715392,3319292539961344]; | ||
test('readVarint & writeVarint', function(t) { | ||
var buf = new Pbf(new Buffer(0)); | ||
for (var i = 0; i < testNumbers.length; i++) { | ||
buf.writeVarint(testNumbers[i]); | ||
} | ||
var len = buf.finish().length; | ||
t.equal(len, 229); | ||
buf.finish(); | ||
i = 0; | ||
while (buf.pos < len) { | ||
t.equal(buf.readVarint(), testNumbers[i++]); | ||
} | ||
t.end(); | ||
}); | ||
test('readVarint & writeVarint handle really big numbers', function(t) { | ||
var buf = new Pbf(); | ||
var bigNum1 = Math.pow(2, 60); | ||
var bigNum2 = Math.pow(2, 69); | ||
buf.writeVarint(bigNum1); | ||
buf.writeVarint(bigNum2); | ||
buf.finish(); | ||
t.equal(buf.readVarint(), bigNum1); | ||
t.equal(buf.readVarint(), bigNum2); | ||
t.end(); | ||
}); | ||
var testSigned = [0,1,2,0,2,-1,11,18,-17,145,369,891,-1859,-798,2780,-13107,12589,-16433,21140,148023,221062,-985141, | ||
494812,-2121059,-2078871,82483,19219191,29094607,35779553,-215357075,-334572816,-991453240,-1677041436,-3781260558, | ||
-6633052788,1049995056,-22854591776,37921771616,-136983944384,187687841024,107420097536,1069000079360,1234936065024, | ||
-2861223108608,-492686688256,-6740322942976,-7061359607808,24638679941120,19583051038720,83969719009280, | ||
52578722775040,416482297118720,1981092523409408,-389256637841408]; | ||
test('readSVarint & writeSVarint', function(t) { | ||
var buf = new Pbf(new Buffer(0)); | ||
for (var i = 0; i < testSigned.length; i++) { | ||
buf.writeSVarint(testSigned[i]); | ||
} | ||
var len = buf.finish().length; | ||
t.equal(len, 224); | ||
buf.finish(); | ||
i = 0; | ||
while (buf.pos < len) { | ||
t.equal(buf.readSVarint(), testSigned[i++]); | ||
} | ||
t.end(); | ||
}); | ||
test('writeVarint throws error on a number that is too big', function(t) { | ||
var buf = new Pbf(new Buffer(0)); | ||
t.throws(function () { | ||
buf.writeVarint(29234322996241367000012); | ||
}); | ||
t.end(); | ||
}); | ||
test('readVarint throws error on a number that is longer than 10 bytes', function(t) { | ||
var buf = new Pbf(new Buffer([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])); | ||
t.throws(function () { | ||
buf.readVarint(); | ||
}); | ||
t.end(); | ||
}); | ||
test('readBoolean & writeBoolean', function(t) { | ||
var buf = new Pbf(); | ||
buf.writeBoolean(true); | ||
buf.writeBoolean(false); | ||
buf.finish(); | ||
t.equal(buf.readBoolean(), true); | ||
t.equal(buf.readBoolean(), false); | ||
t.end(); | ||
}); | ||
test('readBytes', function(t) { | ||
var buf = new Pbf([8, 1, 2, 3, 4, 5, 6, 7, 8]); | ||
t.same(buf.readBytes(), [1, 2, 3, 4, 5, 6, 7, 8]); | ||
t.end(); | ||
}); | ||
test('writeBytes', function(t) { | ||
var buf = new Pbf(); | ||
buf.writeBytes([1, 2, 3, 4, 5, 6, 7, 8]); | ||
var bytes = buf.finish(); | ||
t.same(toArray(bytes), [8, 1, 2, 3, 4, 5, 6, 7, 8]); | ||
t.end(); | ||
}); | ||
test('readDouble', function(t) { | ||
var buffer = new Buffer(8); | ||
buffer.writeDoubleLE(42, 0); | ||
buffer.writeDoubleLE(12345.6789012345, 0); | ||
var buf = new Pbf(buffer); | ||
t.equal(buf.readDouble(), 42); | ||
t.equal(Math.round(buf.readDouble() * 1e10) / 1e10, 12345.6789012345); | ||
t.end(); | ||
}); | ||
test('readUInt32', function(t) { | ||
test('readPacked and writePacked', function(t) { | ||
var buf = new Pbf(); | ||
buf.writePacked('Varint', 1, []); | ||
t.equal(buf.pos, 0); | ||
buf.writePacked('Varint', 1, testNumbers); | ||
buf.finish(); | ||
buf.readFields(function (tag) { | ||
if (tag === 1) t.same(buf.readPacked('Varint'), testNumbers); | ||
else t.fail('wrong tag encountered: ' + tag); | ||
}); | ||
t.end(); | ||
}); | ||
test('writeDouble', function(t) { | ||
var buf = new Pbf(new Buffer(8)); | ||
buf.writeDouble(12345.6789012345); | ||
buf.finish(); | ||
t.equal(Math.round(buf.readDouble() * 1e10) / 1e10, 12345.6789012345); | ||
t.end(); | ||
}); | ||
test('readFloat', function(t) { | ||
var buffer = new Buffer(4); | ||
buffer.writeFloatLE(123.456, 0); | ||
var buf = new Pbf(buffer); | ||
t.equal(Math.round(1000 * buf.readFloat()) / 1000, 123.456); | ||
t.end(); | ||
}); | ||
test('writeFloat', function(t) { | ||
var buf = new Pbf(new Buffer(4)); | ||
buf.writeFloat(123.456); | ||
buf.finish(); | ||
t.equal(Math.round(1000 * buf.readFloat()) / 1000, 123.456); | ||
t.end(); | ||
}); | ||
test('readFixed32', function(t) { | ||
var buffer = new Buffer(16); | ||
@@ -37,5 +180,134 @@ buffer.writeUInt32LE(42, 0); | ||
var buf = new Pbf(buffer); | ||
t.equal(buf.readUInt32(), 42); | ||
t.equal(buf.readUInt32(), 24); | ||
t.equal(buf.readFixed32(), 42); | ||
t.equal(buf.readFixed32(), 24); | ||
t.end(); | ||
}); | ||
test('writeFixed32', function(t) { | ||
var buf = new Pbf(new Buffer(16)); | ||
buf.writeFixed32(42); | ||
buf.writeFixed32(24); | ||
buf.finish(); | ||
t.equal(buf.readFixed32(), 42); | ||
t.equal(buf.readFixed32(), 24); | ||
t.end(); | ||
}); | ||
test('readFixed64', function (t) { | ||
var buf = new Pbf(new Buffer(8)); | ||
buf.writeFixed64(102451124123); | ||
buf.finish(); | ||
t.same(buf.readFixed64(), 102451124123); | ||
t.end(); | ||
}); | ||
test('writeFixed64', function (t) { | ||
var buf = new Pbf(new Buffer(8)); | ||
buf.writeFixed64(102451124123); | ||
t.same(toArray(buf.buf), [155,23,144,218,23,0,0,0]); | ||
t.end(); | ||
}); | ||
test('writeString', function (t) { | ||
var buffer = new Buffer(32); | ||
var buf = new Pbf(buffer); | ||
var len = Buffer.byteLength('Привет'); | ||
buf.writeVarint(len); | ||
buffer.write('Привет', buf.pos); | ||
buf.pos += len; | ||
buf.finish(); | ||
t.equal(buf.readString(), 'Привет'); | ||
t.end(); | ||
}); | ||
test('readString', function (t) { | ||
var buf = new Pbf(new Buffer(0)); | ||
buf.writeString('Привет'); | ||
buf.finish(); | ||
t.equal(buf.readString(), 'Привет'); | ||
t.end(); | ||
}); | ||
test('readFields', function (t) { | ||
var buf = new Pbf(fs.readFileSync(__dirname + '/fixtures/12665.vector.pbf')), | ||
layerOffsets = []; | ||
buf.readFields(function (tag) { | ||
if (tag == 3) layerOffsets.push(buf.pos); | ||
}); | ||
t.ok(buf.pos >= buf.length); | ||
t.same(layerOffsets, [1,2490,2581,2819,47298,47626,55732,56022,56456,88178,112554]); | ||
t.end(); | ||
}); | ||
test('readMessage', function (t) { | ||
var buf = new Pbf(fs.readFileSync(__dirname + '/fixtures/12665.vector.pbf')), | ||
layerNames = []; | ||
buf.readFields(function (tag) { | ||
if (tag == 3) buf.readMessage(readLayer); | ||
}); | ||
function readLayer(tag) { | ||
if (tag === 1) layerNames.push(buf.readString()); | ||
} | ||
t.same(layerNames, ["landuse","water","barrier_line","building","tunnel","road", | ||
"place_label","water_label","poi_label","road_label","housenum_label"]); | ||
t.end(); | ||
}); | ||
test('field writing methods', function (t) { | ||
var buf = new Pbf(); | ||
buf.writeFixed32Field(1, 100); | ||
buf.writeFixed64Field(2, 200); | ||
buf.writeVarintField(3, 1234); | ||
buf.writeSVarintField(4, -599); | ||
buf.writeStringField(5, 'Hello world'); | ||
buf.writeFloatField(6, 123); | ||
buf.writeDoubleField(7, 123); | ||
buf.writeBooleanField(8, true); | ||
buf.writeBytesField(9, [1, 2, 3]); | ||
var message = new Pbf(); | ||
message.writeBooleanField(1, true); | ||
buf.writeMessage(10, message); | ||
buf.finish(); | ||
buf.readFields(function (tag) { | ||
if (tag === 1) buf.readFixed32(); | ||
else if (tag === 2) buf.readFixed64(); | ||
else if (tag === 3) buf.readVarint(); | ||
else if (tag === 4) buf.readSVarint(); | ||
else if (tag === 5) buf.readString(); | ||
else if (tag === 6) buf.readFloat(); | ||
else if (tag === 7) buf.readDouble(); | ||
else if (tag === 8) buf.readBoolean(); | ||
else if (tag === 9) buf.readBytes(); | ||
else if (tag === 10) buf.readMessage(function () { /* skip */ }); | ||
else t.fail('unknown tag'); | ||
}); | ||
t.end(); | ||
}); | ||
test('skip', function (t) { | ||
var buf = new Pbf(); | ||
buf.writeFixed32Field(1, 100); | ||
buf.writeFixed64Field(2, 200); | ||
buf.writeVarintField(3, 1234); | ||
buf.writeStringField(4, 'Hello world'); | ||
buf.finish(); | ||
buf.readFields(function () { /* skip */ }); | ||
t.equal(buf.pos, buf.length); | ||
t.throws(function () { | ||
buf.skip(6); | ||
}); | ||
t.end(); | ||
}); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
157191
11
815
0
150
2
9
2