430 lines
8.6 KiB
JavaScript
430 lines
8.6 KiB
JavaScript
/*!
|
|
* writer.js - buffer writer for bcoin
|
|
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
|
|
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
|
|
* https://github.com/bcoin-org/bcoin
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
var assert = require('assert');
|
|
var encoding = require('./encoding');
|
|
var crypto = require('../crypto/crypto');
|
|
|
|
/**
|
|
* An object that allows writing of buffers in a
|
|
* sane manner. This buffer writer is extremely
|
|
* optimized since it does not actually write
|
|
* anything until `render` is called. It makes
|
|
* one allocation: at the end, once it knows the
|
|
* size of the buffer to be allocated. Because
|
|
* of this, it can also act as a size calculator
|
|
* which is useful for guaging block size
|
|
* without actually serializing any data.
|
|
* @exports StaticWriter
|
|
* @constructor
|
|
* @param {(StaticWriter|Object)?} options
|
|
*/
|
|
|
|
function StaticWriter(size) {
|
|
if (!(this instanceof StaticWriter))
|
|
return new StaticWriter(size);
|
|
|
|
this.data = new Buffer(size);
|
|
this.written = 0;
|
|
}
|
|
|
|
/**
|
|
* Allocate and render the final buffer.
|
|
* @param {Boolean?} keep - Do not destroy the writer.
|
|
* @returns {Buffer} Rendered buffer.
|
|
*/
|
|
|
|
StaticWriter.prototype.render = function render(keep) {
|
|
var data = this.data;
|
|
|
|
assert.equal(this.written, data.length);
|
|
|
|
if (!keep)
|
|
this.destroy();
|
|
|
|
return data;
|
|
};
|
|
|
|
/**
|
|
* Get size of data written so far.
|
|
* @returns {Number}
|
|
*/
|
|
|
|
StaticWriter.prototype.getSize = function getSize() {
|
|
return this.written;
|
|
};
|
|
|
|
/**
|
|
* Seek to relative offset.
|
|
* @param {Number} offset
|
|
*/
|
|
|
|
StaticWriter.prototype.seek = function seek(offset) {
|
|
this.written += offset;
|
|
};
|
|
|
|
/**
|
|
* Destroy the buffer writer.
|
|
*/
|
|
|
|
StaticWriter.prototype.destroy = function destroy() {
|
|
this.data = null;
|
|
this.written = null;
|
|
};
|
|
|
|
/**
|
|
* Write uint8.
|
|
* @param {Number} value
|
|
*/
|
|
|
|
StaticWriter.prototype.writeU8 = function writeU8(value) {
|
|
this.written = this.data.writeUInt8(value, this.written, true);
|
|
};
|
|
|
|
/**
|
|
* Write uint16le.
|
|
* @param {Number} value
|
|
*/
|
|
|
|
StaticWriter.prototype.writeU16 = function writeU16(value) {
|
|
this.written = this.data.writeUInt16LE(value, this.written, true);
|
|
};
|
|
|
|
/**
|
|
* Write uint16be.
|
|
* @param {Number} value
|
|
*/
|
|
|
|
StaticWriter.prototype.writeU16BE = function writeU16BE(value) {
|
|
this.written = this.data.writeUInt16BE(value, this.written, true);
|
|
};
|
|
|
|
/**
|
|
* Write uint32le.
|
|
* @param {Number} value
|
|
*/
|
|
|
|
StaticWriter.prototype.writeU32 = function writeU32(value) {
|
|
this.written = this.data.writeUInt32LE(value, this.written, true);
|
|
};
|
|
|
|
/**
|
|
* Write uint32be.
|
|
* @param {Number} value
|
|
*/
|
|
|
|
StaticWriter.prototype.writeU32BE = function writeU32BE(value) {
|
|
this.written = this.data.writeUInt32BE(value, this.written, true);
|
|
};
|
|
|
|
/**
|
|
* Write uint64le.
|
|
* @param {Number} value
|
|
*/
|
|
|
|
StaticWriter.prototype.writeU64 = function writeU64(value) {
|
|
this.written = encoding.writeU64(this.data, value, this.written);
|
|
};
|
|
|
|
/**
|
|
* Write uint64be.
|
|
* @param {Number} value
|
|
*/
|
|
|
|
StaticWriter.prototype.writeU64BE = function writeU64BE(value) {
|
|
this.written = encoding.writeU64BE(this.data, value, this.written);
|
|
};
|
|
|
|
/**
|
|
* Write uint64le.
|
|
* @param {BN} value
|
|
*/
|
|
|
|
StaticWriter.prototype.writeU64BN = function writeU64BN(value) {
|
|
assert(false, 'Not implemented.');
|
|
};
|
|
|
|
/**
|
|
* Write uint64be.
|
|
* @param {BN} value
|
|
*/
|
|
|
|
StaticWriter.prototype.writeU64BEBN = function writeU64BEBN(value) {
|
|
assert(false, 'Not implemented.');
|
|
};
|
|
|
|
/**
|
|
* Write int8.
|
|
* @param {Number} value
|
|
*/
|
|
|
|
StaticWriter.prototype.write8 = function write8(value) {
|
|
this.written = this.data.writeInt8(value, this.written, true);
|
|
};
|
|
|
|
/**
|
|
* Write int16le.
|
|
* @param {Number} value
|
|
*/
|
|
|
|
StaticWriter.prototype.write16 = function write16(value) {
|
|
this.written = this.data.writeInt16LE(value, this.written, true);
|
|
};
|
|
|
|
/**
|
|
* Write int16be.
|
|
* @param {Number} value
|
|
*/
|
|
|
|
StaticWriter.prototype.write16BE = function write16BE(value) {
|
|
this.written = this.data.writeInt16BE(value, this.written, true);
|
|
};
|
|
|
|
/**
|
|
* Write int32le.
|
|
* @param {Number} value
|
|
*/
|
|
|
|
StaticWriter.prototype.write32 = function write32(value) {
|
|
this.written = this.data.writeInt32LE(value, this.written, true);
|
|
};
|
|
|
|
/**
|
|
* Write int32be.
|
|
* @param {Number} value
|
|
*/
|
|
|
|
StaticWriter.prototype.write32BE = function write32BE(value) {
|
|
this.written = this.data.writeInt32BE(value, this.written, true);
|
|
};
|
|
|
|
/**
|
|
* Write int64le.
|
|
* @param {Number} value
|
|
*/
|
|
|
|
StaticWriter.prototype.write64 = function write64(value) {
|
|
this.written = encoding.write64(this.data, value, this.written);
|
|
};
|
|
|
|
/**
|
|
* Write int64be.
|
|
* @param {Number} value
|
|
*/
|
|
|
|
StaticWriter.prototype.write64BE = function write64BE(value) {
|
|
this.written = encoding.write64BE(this.data, value, this.written);
|
|
};
|
|
|
|
/**
|
|
* Write int64le.
|
|
* @param {BN} value
|
|
*/
|
|
|
|
StaticWriter.prototype.write64BN = function write64BN(value) {
|
|
assert(false, 'Not implemented.');
|
|
};
|
|
|
|
/**
|
|
* Write int64be.
|
|
* @param {BN} value
|
|
*/
|
|
|
|
StaticWriter.prototype.write64BEBN = function write64BEBN(value) {
|
|
assert(false, 'Not implemented.');
|
|
};
|
|
|
|
/**
|
|
* Write float le.
|
|
* @param {Number} value
|
|
*/
|
|
|
|
StaticWriter.prototype.writeFloat = function writeFloat(value) {
|
|
this.written = this.data.writeFloatLE(value, this.written, true);
|
|
};
|
|
|
|
/**
|
|
* Write float be.
|
|
* @param {Number} value
|
|
*/
|
|
|
|
StaticWriter.prototype.writeFloatBE = function writeFloatBE(value) {
|
|
this.written = this.data.writeFloatBE(value, this.written, true);
|
|
};
|
|
|
|
/**
|
|
* Write double le.
|
|
* @param {Number} value
|
|
*/
|
|
|
|
StaticWriter.prototype.writeDouble = function writeDouble(value) {
|
|
this.written = this.data.writeDoubleLE(value, this.written, true);
|
|
};
|
|
|
|
/**
|
|
* Write double be.
|
|
* @param {Number} value
|
|
*/
|
|
|
|
StaticWriter.prototype.writeDoubleBE = function writeDoubleBE(value) {
|
|
this.written = this.data.writeDoubleBE(value, this.written, true);
|
|
};
|
|
|
|
/**
|
|
* Write a varint.
|
|
* @param {Number} value
|
|
*/
|
|
|
|
StaticWriter.prototype.writeVarint = function writeVarint(value) {
|
|
this.written = encoding.writeVarint(this.data, value, this.written);
|
|
};
|
|
|
|
/**
|
|
* Write a varint.
|
|
* @param {BN} value
|
|
*/
|
|
|
|
StaticWriter.prototype.writeVarintBN = function writeVarintBN(value) {
|
|
assert(false, 'Not implemented.');
|
|
};
|
|
|
|
/**
|
|
* Write a varint (type 2).
|
|
* @param {Number} value
|
|
*/
|
|
|
|
StaticWriter.prototype.writeVarint2 = function writeVarint2(value) {
|
|
this.written = encoding.writeVarint2(this.data, value, this.written);
|
|
};
|
|
|
|
/**
|
|
* Write a varint (type 2).
|
|
* @param {BN} value
|
|
*/
|
|
|
|
StaticWriter.prototype.writeVarint2BN = function writeVarint2BN(value) {
|
|
assert(false, 'Not implemented.');
|
|
};
|
|
|
|
/**
|
|
* Write bytes.
|
|
* @param {Buffer} value
|
|
*/
|
|
|
|
StaticWriter.prototype.writeBytes = function writeBytes(value) {
|
|
if (value.length === 0)
|
|
return;
|
|
|
|
this.written += value.copy(this.data, this.written);
|
|
};
|
|
|
|
/**
|
|
* Write bytes with a varint length before them.
|
|
* @param {Buffer} value
|
|
*/
|
|
|
|
StaticWriter.prototype.writeVarBytes = function writeVarBytes(value) {
|
|
this.writeVarint(value.length);
|
|
|
|
if (value.length === 0)
|
|
return;
|
|
|
|
this.writeBytes(value);
|
|
};
|
|
|
|
/**
|
|
* Write string to buffer.
|
|
* @param {String|Buffer} value
|
|
* @param {String?} enc - Any buffer-supported encoding.
|
|
*/
|
|
|
|
StaticWriter.prototype.writeString = function writeString(value, enc) {
|
|
if (typeof value !== 'string')
|
|
return this.writeBytes(value);
|
|
|
|
if (value.length === 0)
|
|
return;
|
|
|
|
this.written += this.data.write(value, this.written, enc);
|
|
};
|
|
|
|
/**
|
|
* Write a hash/hex-string.
|
|
* @param {Hash|Buffer}
|
|
*/
|
|
|
|
StaticWriter.prototype.writeHash = function writeHash(value) {
|
|
this.writeString(value, 'hex');
|
|
};
|
|
|
|
/**
|
|
* Write a string with a varint length before it.
|
|
* @param {String|Buffer}
|
|
* @param {String?} enc - Any buffer-supported encoding.
|
|
*/
|
|
|
|
StaticWriter.prototype.writeVarString = function writeVarString(value, enc) {
|
|
var size;
|
|
|
|
if (typeof value !== 'string')
|
|
return this.writeVarBytes(value);
|
|
|
|
size = Buffer.byteLength(value, enc);
|
|
|
|
this.writeVarint(size);
|
|
|
|
if (value.length === 0)
|
|
return;
|
|
|
|
this.writeString(value, enc);
|
|
};
|
|
|
|
/**
|
|
* Write a null-terminated string.
|
|
* @param {String|Buffer}
|
|
* @param {String?} enc - Any buffer-supported encoding.
|
|
*/
|
|
|
|
StaticWriter.prototype.writeNullString = function writeNullString(value, enc) {
|
|
this.writeString(value, enc);
|
|
this.writeU8(0);
|
|
};
|
|
|
|
/**
|
|
* Calculate and write a checksum for the data written so far.
|
|
*/
|
|
|
|
StaticWriter.prototype.writeChecksum = function writeChecksum() {
|
|
var data = this.data.slice(0, this.written);
|
|
var hash = crypto.hash256(data);
|
|
this.written += hash.copy(this.data, this.written, 0, 4);
|
|
};
|
|
|
|
/**
|
|
* Fill N bytes with value.
|
|
* @param {Number} value
|
|
* @param {Number} size
|
|
*/
|
|
|
|
StaticWriter.prototype.fill = function fill(value, size) {
|
|
assert(size >= 0);
|
|
|
|
if (size === 0)
|
|
return;
|
|
|
|
this.data.fill(value, this.written, this.written + size);
|
|
this.written += size;
|
|
};
|
|
|
|
/*
|
|
* Expose
|
|
*/
|
|
|
|
module.exports = StaticWriter;
|