Skip to content

Commit

Permalink
Handle 64 bit numbers
Browse files Browse the repository at this point in the history
  • Loading branch information
zachasme committed Dec 12, 2019
1 parent 89ed773 commit 35b17f8
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 26 deletions.
8 changes: 4 additions & 4 deletions compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,9 @@ function compileFieldRead(ctx, field) {
case 'bool': return prefix + 'Boolean' + suffix;
case 'enum':
case 'uint32':
case 'int32': return prefix + 'Varint' + suffix;
case 'uint64':
case 'int32':
case 'int64': return prefix + 'Varint' + suffix;
case 'int64': return prefix + 'Varint64' + suffix;
case 'sint32':
case 'sint64': return prefix + 'SVarint' + suffix;
case 'fixed32': return prefix + 'Fixed32' + suffix;
Expand Down Expand Up @@ -178,9 +178,9 @@ function compileFieldWrite(ctx, field, name) {
case 'bool': return prefix + 'Boolean' + postfix;
case 'enum':
case 'uint32':
case 'int32': return prefix + 'Varint' + postfix;
case 'uint64':
case 'int32':
case 'int64': return prefix + 'Varint' + postfix;
case 'int64': return prefix + 'Varint64' + postfix;
case 'sint32':
case 'sint64': return prefix + 'SVarint' + postfix;
case 'fixed32': return prefix + 'Fixed32' + postfix;
Expand Down
68 changes: 51 additions & 17 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable new-cap, no-undef */
'use strict';

module.exports = Pbf;
Expand Down Expand Up @@ -90,7 +91,7 @@ Pbf.prototype = {
return val;
},

readVarint: function(isSigned) {
readVarint: function(isSigned, is64) {
var buf = this.buf,
val, b;

Expand All @@ -100,11 +101,11 @@ Pbf.prototype = {
b = buf[this.pos++]; val |= (b & 0x7f) << 21; if (b < 0x80) return val;
b = buf[this.pos]; val |= (b & 0x0f) << 28;

return readVarintRemainder(val, isSigned, this);
return readVarintRemainder(val, isSigned, is64, this);
},

readVarint64: function() { // for compatibility with v2.0.1
return this.readVarint(true);
readVarint64: function(isSigned) {
return this.readVarint(isSigned, true);
},

readSVarint: function() {
Expand Down Expand Up @@ -266,7 +267,7 @@ Pbf.prototype = {
val = +val || 0;

if (val > 0xfffffff || val < 0) {
writeBigVarint(val, this);
writeBigVarint(BigInt(val), this);
return;
}

Expand All @@ -282,6 +283,24 @@ Pbf.prototype = {
this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2);
},

writeVarint64: function(val) {
val = BigInt(val);

if (val > 0xfffffff || val < 0) {
writeBigVarint(val, this);
return;
}

val = Number(val);

this.realloc(4);

this.buf[this.pos++] = val & 0x7f | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return;
this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return;
this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return;
this.buf[this.pos++] = (val >>> 7) & 0x7f;
},

writeBoolean: function(val) {
this.writeVarint(Boolean(val));
},
Expand Down Expand Up @@ -379,6 +398,10 @@ Pbf.prototype = {
this.writeTag(tag, Pbf.Varint);
this.writeVarint(val);
},
writeVarint64Field: function(tag, val) {
this.writeTag(tag, Pbf.Varint);
this.writeVarint64(val);
},
writeSVarintField: function(tag, val) {
this.writeTag(tag, Pbf.Varint);
this.writeSVarint(val);
Expand All @@ -400,16 +423,16 @@ Pbf.prototype = {
}
};

function readVarintRemainder(l, s, p) {
function readVarintRemainder(l, s, is64, p) {
var buf = p.buf,
h, b;

b = buf[p.pos++]; h = (b & 0x70) >> 4; if (b < 0x80) return toNum(l, h, s);
b = buf[p.pos++]; h |= (b & 0x7f) << 3; if (b < 0x80) return toNum(l, h, s);
b = buf[p.pos++]; h |= (b & 0x7f) << 10; if (b < 0x80) return toNum(l, h, s);
b = buf[p.pos++]; h |= (b & 0x7f) << 17; if (b < 0x80) return toNum(l, h, s);
b = buf[p.pos++]; h |= (b & 0x7f) << 24; if (b < 0x80) return toNum(l, h, s);
b = buf[p.pos++]; h |= (b & 0x01) << 31; if (b < 0x80) return toNum(l, h, s);
b = buf[p.pos++]; h = (b & 0x70) >> 4; if (b < 0x80) return toNum(l, h, s, is64);
b = buf[p.pos++]; h |= (b & 0x7f) << 3; if (b < 0x80) return toNum(l, h, s, is64);
b = buf[p.pos++]; h |= (b & 0x7f) << 10; if (b < 0x80) return toNum(l, h, s, is64);
b = buf[p.pos++]; h |= (b & 0x7f) << 17; if (b < 0x80) return toNum(l, h, s, is64);
b = buf[p.pos++]; h |= (b & 0x7f) << 24; if (b < 0x80) return toNum(l, h, s, is64);
b = buf[p.pos++]; h |= (b & 0x01) << 31; if (b < 0x80) return toNum(l, h, s, is64);

throw new Error('Expected varint not more than 10 bytes');
}
Expand All @@ -419,7 +442,18 @@ function readPackedEnd(pbf) {
pbf.readVarint() + pbf.pos : pbf.pos + 1;
}

function toNum(low, high, isSigned) {
function toNum(low, high, isSigned, is64) {
if (is64) {
var int;
if (isSigned) {
int = BigInt(high) * BigInt(0x100000000) + BigInt(low >>> 0);
return int.toString();
}

int = (BigInt(high >>> 0) * BigInt(0x100000000)) + BigInt(low >>> 0);
return int.toString();
}

if (isSigned) {
return high * 0x100000000 + (low >>> 0);
}
Expand All @@ -431,11 +465,11 @@ function writeBigVarint(val, pbf) {
var low, high;

if (val >= 0) {
low = (val % 0x100000000) | 0;
high = (val / 0x100000000) | 0;
low = Number(val % BigInt(0x100000000)) | 0;
high = Number(val / BigInt(0x100000000)) | 0;
} else {
low = ~(-val % 0x100000000);
high = ~(-val / 0x100000000);
low = ~Number(-val % BigInt(0x100000000));
high = ~Number(-val / BigInt(0x100000000));

if (low ^ 0xffffffff) {
low = (low + 1) | 0;
Expand Down
8 changes: 4 additions & 4 deletions test/compile.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,14 +259,14 @@ test('handles negative varint', function(t) {

Envelope.write({
int: -5,
long: -10
long: '-10'
}, pbf);

var buf = pbf.finish();
var data = Envelope.read(new Pbf(buf));

t.equals(data.int, -5);
t.equals(data.long, -10);
t.equals(data.long, '-10');

t.end();
});
Expand All @@ -278,14 +278,14 @@ test('handles unsigned varint', function(t) {

Envelope.write({
uint: Math.pow(2, 31),
ulong: Math.pow(2, 63)
ulong: '18446744073709551615'
}, pbf);

var buf = pbf.finish();
var data = Envelope.read(new Pbf(buf));

t.equals(data.uint, Math.pow(2, 31));
t.equals(data.ulong, Math.pow(2, 63));
t.equals(data.ulong, '18446744073709551615');

t.end();
});
2 changes: 1 addition & 1 deletion test/pbf.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ test('readVarint signed', function(t) {
test('readVarint64 (compatibility)', function(t) {
var bytes = [0xc8,0xe8,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x01];
var buf = new Pbf(new Buffer(bytes));
t.equal(buf.readVarint64(), -3000);
t.equal(buf.readVarint64(true), '-3000');
t.end();
});

Expand Down

0 comments on commit 35b17f8

Please sign in to comment.