diffusion
Version:
Diffusion JavaScript client
328 lines (281 loc) • 7.66 kB
JavaScript
/*eslint valid-jsdoc: "off"*/
var Long = require('long');
// Bitmasks for int64 read/write
var x80 = Long.fromNumber(0x80),
x7F = Long.fromNumber(0x7F),
// Long.not returns a different value than ~
x7FInv = x7F.not(); //Long.fromNumber(~0x7F);
/**
* Helper function
* @private
*/
var readOneByte = function(input) {
var i = input.read();
if (i === -1) {
throw new Error("End of stream");
}
return i;
};
/**
* Javascript implementation of Encoded Data Codec, used for Command Service serialisers
*
* @namespace
* @alias Encoded Data Codec
*/
var codec = {};
/**
* Read an encoded Int64.
* <P>
* This will return the value as a Long instance.
*
* @param {BufferInputStream} - The input stream from which to read
* @returns {Long} The decoded Int64, represented as Long
* @throws A malformed error if an int64 cannot be read.
*/
codec.readInt64 = function(input) {
var result = Long.fromNumber(0), shift = 0;
while (shift < 64) {
var i = readOneByte(input),
l = Long.fromNumber(i);
result = result.or(l.and(x7F).shiftLeft(shift));
if (l.and(x80).equals(0)) {
return result;
}
shift += 7;
}
throw "Malformed int64";
};
/**
* Write an encoded Int64.
* <P>
* Writes a number as an Int64 to the given Output stream.
*
* @param {BufferOutputStream} - The output stream to write to
* @param {Number} - The number to write
*/
codec.writeInt64 = function(bos, value) {
var int64 = value instanceof Long ? value : Long.fromNumber(value, false);
for (;;) {
if (int64.and(x7FInv).equals(0)) {
bos.write(int64.toInt());
return;
} else {
bos.write(int64.and(x7F).or(x80).toInt());
int64 = int64.shiftRightUnsigned(7);
}
}
};
/**
* Read an encoded Int32.
*
* @param {BufferInputStream} - The input stream to read from.
* @returns {Number} The Int32 that was read
* @throws A malformed error if an int32 cannot be read
*/
codec.readInt32 = function(bis) {
var shift = 0,
result = 0;
while (shift < 32) {
var i = readOneByte(bis);
result |= (i & 0x7F) << shift;
if ((i & 0x80) === 0) {
return result;
}
shift += 7;
}
throw "Malformed int32";
};
/**
* Write an encoded Int32.
*
* @param {BufferOutputStream} - The output stream to write to.
* @param {Number} - The number to write as an int32.
*/
codec.writeInt32 = function(bos, value) {
for (;;) {
if ((value & ~0x7F) === 0) {
bos.write(value);
return;
} else {
bos.write((value & 0x7F) | 0x80);
value = value >>> 7;
}
}
};
/**
* Write a single signed byte.
*
* @param {BufferOutputStream} - The output stream to write to.
* @param {Number} - The byte value to write. Must be between -128 & 127.
*/
codec.writeByte = function(bos, value) {
bos.writeInt8(value);
if ((value & ~0x7F) !== 0) {
bos.write(1);
}
};
/**
* Read a single signed byte.
*
* @param {BufferInputStream} - The input stream to read from.
* @returns {Number} - The byte that was read.
* @throws A malformed error if the byte couldn't be read.
*/
codec.readByte = function(bis) {
var b1 = bis.readInt8();
if ((b1 & ~0x7F) === 0) {
return b1;
}
var b2 = readOneByte(bis);
if (b2 !== 1) {
throw "Malformed byte";
}
return (b1 | 0x80);
};
/**
* Read bytes as a Buffer.
*
* @param {BufferInputStream} - The input stream to read from.
* @returns {Buffer} - The bytes that were read.
*/
codec.readBytes = function(bis) {
var length = codec.readInt32(bis);
return bis.readMany(length);
};
/**
* Write multiple bytes.
*
* @param {BufferOutputStream} - The output stream to write to.
* @param {Buffer} - The bytes to be written.
*/
codec.writeBytes = function(bos, value) {
codec.writeInt32(bos, value.length);
bos.writeMany(value);
};
/**
* Read a UTF-8 encoded String.
*
* @param {BufferInputStream} - The input stream to read from.
* @returns {String} The string that was read.
*/
codec.readString = function(bis) {
var buffer = codec.readBytes(bis);
return buffer ? buffer.toString('utf8') : "";
};
/**
* Write a string using UTF-8 encoding.
*
* @param {BufferOutputStream} - The output stream to write to.
* @param {String} - The string to write.
*/
codec.writeString = function(bos, value) {
codec.writeBytes(bos, new Buffer(value, 'utf8'));
};
/**
* Write a collection of objects, using a specific writer function
*
* @param {BufferOutputStream} - The output stream to write to
* @param {Array} - Array of values
* @param {Function} - Writer function
*/
codec.writeCollection = function(bos, arr, write) {
codec.writeInt32(bos, arr.length);
for (var i = 0; i < arr.length; ++i) {
write(bos, arr[i]);
}
};
/**
* Read a collection of objects, using a specific reader function
*
* @param {BufferInputStream} - The inpit stream to read from
* @param {Function} - Reader function
* @returns {Array} An array of read values
*/
codec.readCollection = function(bis, read) {
var length = codec.readInt32(bis);
var arr = [];
for (var i = 0; i < length; ++i) {
arr.push(read(bis));
}
return arr;
};
/**
* Read a dictionary of strings and values of a given type.
*
* @param {BufferInputStream} - The input stream to read from
* @param {Function} - Value reader function
* @returns {Object.<String, Object>} A dictionary of values
*/
codec.readDictionary = function(bis, read) {
return codec.readMap(bis, codec.readString, read);
};
/**
* Write a dictionary of strings and values.
*
* @param {BufferOutputStream} - The output stream to write to
* @param {Object.<String, Object>} - The dictionary of values
* @param {Function} - Value writer function
*/
codec.writeDictionary = function(bos, dict, write) {
codec.writeMap(bos, dict, codec.writeString, write);
};
/**
* Write a map of keys/values.
*
* @param {BufferOutputStream} bos - The output stream to write to
* @param {Object} dict - The map of values
* @param {Function} key - The Key writer function
* @param {Function} value - The Value writer function
*/
codec.writeMap = function(bos, dict, key, value) {
codec.writeInt32(bos, Object.keys(dict).length);
for (var k in dict) {
key(bos, k);
value(bos, dict[k]);
}
};
/**
* Read a map of keys/values.
*
* @param {BufferOutputStream} bos - The output stream to write to
* @param {Object} dict - The map of values
* @param {Function} key - The Key reader function
* @param {Function} value - The Value reader function
* @returns {Object} The read map
*/
codec.readMap = function(bis, key, value) {
var length = codec.readInt32(bis);
var dict = {};
for (var i = 0; i < length; ++i) {
var k = key(bis);
dict[k] = value(bis);
}
return dict;
};
/**
* Read a boolean value.
*
* @param {BufferInputStream} - The input stream to read from.
* @returns {boolean} - The boolean that was read.
*/
codec.readBoolean = function(bis) {
var b = bis.readInt8();
if (b === 0) {
return false;
}
return true;
};
/**
* Write a boolean value.
*
* @param {BufferOutputStream} - The output stream to write to.
* @param {value} - The boolean value to write.
*/
codec.writeBoolean = function(bos, value) {
if (value) {
bos.writeInt8(1);
} else {
bos.writeInt8(0);
}
};
module.exports = codec;