181 lines
3.5 KiB
JavaScript
181 lines
3.5 KiB
JavaScript
/*!
|
|
* protowriter.js - protobufs for bcoin
|
|
* Copyright (c) 2016-2017, Christopher Jeffrey (MIT License).
|
|
* https://github.com/bcoin-org/bcoin
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
/**
|
|
* @module utils/protobuf
|
|
*/
|
|
|
|
var assert = require('assert');
|
|
var util = require('../utils/util');
|
|
var BufferWriter = require('../utils/writer');
|
|
|
|
/*
|
|
* Constants
|
|
*/
|
|
|
|
var wireType = {
|
|
VARINT: 0,
|
|
FIXED64: 1,
|
|
DELIMITED: 2,
|
|
START_GROUP: 3,
|
|
END_GROUP: 4,
|
|
FIXED32: 5
|
|
};
|
|
|
|
/**
|
|
* ProtoBuf Writer
|
|
* @alias module:utils.ProtoWriter
|
|
* @constructor
|
|
*/
|
|
|
|
function ProtoWriter() {
|
|
if (!(this instanceof ProtoWriter))
|
|
return new ProtoWriter();
|
|
|
|
BufferWriter.call(this);
|
|
}
|
|
|
|
util.inherits(ProtoWriter, BufferWriter);
|
|
|
|
ProtoWriter.prototype.writeVarint = function _writeVarint(num) {
|
|
var size = sizeVarint(num);
|
|
var value;
|
|
|
|
// Avoid an extra allocation until
|
|
// we make bufferwriter more hackable.
|
|
// More insanity here...
|
|
switch (size) {
|
|
case 6:
|
|
value = slipVarint(num);
|
|
this.writeU32BE(value / 0x10000 | 0);
|
|
this.writeU16BE(value & 0xffff);
|
|
break;
|
|
case 5:
|
|
value = slipVarint(num);
|
|
this.writeU32BE(value / 0x100 | 0);
|
|
this.writeU8(value & 0xff);
|
|
break;
|
|
case 4:
|
|
value = slipVarint(num);
|
|
this.writeU32BE(value);
|
|
break;
|
|
case 3:
|
|
value = slipVarint(num);
|
|
this.writeU16BE(value >> 8);
|
|
this.writeU8(value & 0xff);
|
|
break;
|
|
case 2:
|
|
value = slipVarint(num);
|
|
this.writeU16BE(value);
|
|
break;
|
|
case 1:
|
|
value = slipVarint(num);
|
|
this.writeU8(value);
|
|
break;
|
|
default:
|
|
value = Buffer.allocUnsafe(size);
|
|
writeVarint(value, num, 0);
|
|
this.writeBytes(value);
|
|
break;
|
|
}
|
|
};
|
|
|
|
ProtoWriter.prototype.writeFieldVarint = function writeFieldVarint(tag, value) {
|
|
var header = (tag << 3) | wireType.VARINT;
|
|
this.writeVarint(header);
|
|
this.writeVarint(value);
|
|
};
|
|
|
|
ProtoWriter.prototype.writeFieldU64 = function writeFieldU64(tag, value) {
|
|
assert(util.isSafeInteger(value));
|
|
this.writeFieldVarint(tag, value);
|
|
};
|
|
|
|
ProtoWriter.prototype.writeFieldU32 = function writeFieldU32(tag, value) {
|
|
assert(value <= 0xffffffff);
|
|
this.writeFieldVarint(tag, value);
|
|
};
|
|
|
|
ProtoWriter.prototype.writeFieldBytes = function writeFieldBytes(tag, data) {
|
|
var header = (tag << 3) | wireType.DELIMITED;
|
|
this.writeVarint(header);
|
|
this.writeVarint(data.length);
|
|
this.writeBytes(data);
|
|
};
|
|
|
|
ProtoWriter.prototype.writeFieldString = function writeFieldString(tag, data, enc) {
|
|
if (typeof data === 'string')
|
|
data = Buffer.from(data, enc || 'utf8');
|
|
this.writeFieldBytes(tag, data);
|
|
};
|
|
|
|
/*
|
|
* Encoding
|
|
*/
|
|
|
|
function writeVarint(data, num, off) {
|
|
var ch;
|
|
|
|
assert(util.isSafeInteger(num), 'Number exceeds 2^53-1.');
|
|
|
|
do {
|
|
assert(off < data.length);
|
|
ch = num & 0x7f;
|
|
num -= num % 0x80;
|
|
num /= 0x80;
|
|
if (num !== 0)
|
|
ch |= 0x80;
|
|
data[off] = ch;
|
|
off++;
|
|
} while (num > 0);
|
|
|
|
return off;
|
|
};
|
|
|
|
function slipVarint(num) {
|
|
var data = 0;
|
|
var size = 0;
|
|
var ch;
|
|
|
|
assert(util.isSafeInteger(num), 'Number exceeds 2^53-1.');
|
|
|
|
do {
|
|
assert(size < 7);
|
|
ch = num & 0x7f;
|
|
num -= num % 0x80;
|
|
num /= 0x80;
|
|
if (num !== 0)
|
|
ch |= 0x80;
|
|
data *= 256;
|
|
data += ch;
|
|
size++;
|
|
} while (num > 0);
|
|
|
|
return data;
|
|
}
|
|
|
|
function sizeVarint(num) {
|
|
var size = 0;
|
|
|
|
assert(util.isSafeInteger(num), 'Number exceeds 2^53-1.');
|
|
|
|
do {
|
|
num -= num % 0x80;
|
|
num /= 0x80;
|
|
size++;
|
|
} while (num > 0);
|
|
|
|
return size;
|
|
};
|
|
|
|
/*
|
|
* Expose
|
|
*/
|
|
|
|
module.exports = ProtoWriter;
|