mirror of
https://github.com/mapbox/node-fontnik.git
synced 2026-01-18 15:54:55 +00:00
117 lines
3.6 KiB
JavaScript
117 lines
3.6 KiB
JavaScript
'use strict';
|
|
|
|
var ieee754 = require('./ieee754.js');
|
|
|
|
module.exports = Protobuf;
|
|
function Protobuf(buf) {
|
|
this.buf = buf;
|
|
this.length = buf.length;
|
|
this.pos = 0;
|
|
}
|
|
|
|
Protobuf.prototype.destroy = function() {
|
|
this.buf = null;
|
|
};
|
|
|
|
Protobuf.prototype.readUInt32 = function() {
|
|
var val = this.readUInt32LE(this.pos);
|
|
this.pos += 4;
|
|
return val;
|
|
};
|
|
|
|
Protobuf.prototype.readUInt64 = function() {
|
|
var val = this.readUInt64LE(this.pos);
|
|
this.pos += 8;
|
|
return val;
|
|
};
|
|
|
|
Protobuf.prototype.readDouble = function() {
|
|
var val = ieee754.readIEEE754(this.buf, this.pos, false, 52, 8);
|
|
this.pos += 8;
|
|
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) {
|
|
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(0);
|
|
return 0;
|
|
// throw new Error("TODO: Handle 6+ byte varints");
|
|
}
|
|
};
|
|
|
|
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));
|
|
};
|
|
|
|
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;
|
|
};
|
|
|
|
Protobuf.prototype.readBuffer = function() {
|
|
var bytes = this.readVarint();
|
|
var buffer = this.buf.subarray(this.pos, this.pos + bytes);
|
|
this.pos += bytes;
|
|
return buffer;
|
|
};
|
|
|
|
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;
|
|
};
|
|
|
|
Protobuf.prototype.skip = function(val) {
|
|
// TODO: bounds checking
|
|
var type = val & 0x7;
|
|
switch (type) {
|
|
/* varint */ case 0: while (this.buf[this.pos++] > 0x7f); break;
|
|
/* 64 bit */ case 1: this.pos += 8; break;
|
|
/* length */ case 2: var bytes = this.readVarint(); this.pos += bytes; break;
|
|
/* 32 bit */ case 5: this.pos += 4; break;
|
|
default: throw new Error('Unimplemented type: ' + type);
|
|
}
|
|
};
|