From b21d7aef0d3940b8a7a619caa86c19d66aff1fa2 Mon Sep 17 00:00:00 2001 From: wltsmrz Date: Sun, 6 Oct 2013 02:26:45 -0700 Subject: [PATCH] Cleanup --- src/js/ripple/serializedobject.js | 2 +- src/js/ripple/serializedtypes.js | 335 ++++++++++++++++-------------- 2 files changed, 178 insertions(+), 159 deletions(-) diff --git a/src/js/ripple/serializedobject.js b/src/js/ripple/serializedobject.js index beb69c3c..de19cda2 100644 --- a/src/js/ripple/serializedobject.js +++ b/src/js/ripple/serializedobject.js @@ -156,7 +156,7 @@ SerializedObject.prototype.to_json = function() { var output = { }; while (this.pointer < this.buffer.length) { - var key_and_value = stypes.parse_whatever(this); + var key_and_value = stypes.parse(this); var key = key_and_value[0]; var value = key_and_value[1]; output[key] = SerializedObject.jsonify_structure(value, key); diff --git a/src/js/ripple/serializedtypes.js b/src/js/ripple/serializedtypes.js index 9616bb84..b36c7ac7 100644 --- a/src/js/ripple/serializedtypes.js +++ b/src/js/ripple/serializedtypes.js @@ -6,14 +6,16 @@ * SerializedObject.parse() or SerializedObject.serialize(). */ +var assert = require('assert'); var extend = require('extend'); var utils = require('./utils'); var sjcl = utils.sjcl; -var amount = require('./amount'); var UInt128 = require('./uint128').UInt128; var UInt160 = require('./uint160').UInt160; var UInt256 = require('./uint256').UInt256; + +var amount = require('./amount'); var Amount = amount.Amount; var Currency = amount.Currency; @@ -27,6 +29,26 @@ var SerializedType = function (methods) { extend(this, methods); }; +function isNumber(val) { + return typeof val === 'number' && isFinite(val); +}; + +function isString(val) { + return typeof val === 'string'; +}; + +function isHexInt64String(val) { + return isString(val) && /^[0-9A-F]{0,16}$/i.test(val); +}; + +function isCurrencyString(val) { + return isString(val) && /^[A-Z]{3}$/.test(val); +}; + +function isBigInteger(val) { + return val instanceof BigInteger; +}; + function serialize_hex(so, hexData, noLength) { var byteData = bytes.fromBits(hex.toBits(hexData)); if (!noLength) { @@ -35,18 +57,18 @@ function serialize_hex(so, hexData, noLength) { so.append(byteData); }; - /** * parses bytes as hex */ function convert_bytes_to_hex (byte_array) { return sjcl.codec.hex.fromBits(sjcl.codec.bytes.toBits(byte_array)).toUpperCase(); -} +}; SerializedType.serialize_varint = function (so, val) { if (val < 0) { - throw new Error("Variable integers are unsigned."); + throw new Error('Variable integers are unsigned.'); } + if (val <= 192) { so.append([val]); } else if (val <= 12480) { @@ -60,65 +82,68 @@ SerializedType.serialize_varint = function (so, val) { val & 0xff ]); } else { - throw new Error("Variable integer overflow."); + throw new Error('Variable integer overflow.'); } }; - SerializedType.prototype.parse_varint = function (so) { var b1 = so.read(1)[0], b2, b3; var result; + + if (b1 > 254) { + throw new Error('Invalid varint length indicator'); + } + if (b1 <= 192) { result = b1; } else if (b1 <= 240) { b2 = so.read(1)[0]; - result = 193 + (b1-193)*256 + b2; + result = 193 + (b1 - 193) * 256 + b2; } else if (b1 <= 254) { b2 = so.read(1)[0]; b3 = so.read(1)[0]; - result = 12481 + (b1-241)*65536 + b2*256 + b3 - } - else { - throw new Error("Invalid varint length indicator"); + result = 12481 + (b1 - 241) * 65536 + b2 * 256 + b3 } + return result; }; - - - // In the following, we assume that the inputs are in the proper range. Is this correct? - // Helper functions for 1-, 2-, and 4-byte integers. /** * Convert an integer value into an array of bytes. * - * The result is appended to the serialized object ("so"). + * The result is appended to the serialized object ('so'). */ function append_byte_array(so, val, bytes) { - if (isNaN(val) || val === null) { - throw new Error("Integer is not a number"); + if (!isNumber(val)) { + throw new Error('Value is not a number'); } - if (val < 0 || val >= (Math.pow(256, bytes))) { - throw new Error("Integer out of bounds"); - } - var newBytes = []; - for (var i=0; i>> (i*8) & 0xff); - } - so.append(newBytes); -} -// Convert a certain number of bytes from the serialized object ("so") into an integer. + if (val < 0 || val >= Math.pow(256, bytes)) { + throw new Error('Value out of bounds'); + } + + var newBytes = [ ]; + + for (var i=0; i>> (i * 8) & 0xff); + } + + so.append(newBytes); +}; + +// Convert a certain number of bytes from the serialized object ('so') into an integer. function readAndSum(so, bytes) { var sum = 0; - for (var i=0; i 16) { - throw new Error("Int64 is too large"); + throw new Error('Int64 is too large'); } while (hex.length < 16) { - hex = "0" + hex; + hex = '0' + hex; } return serialize_hex(so, hex, true); //noLength = true @@ -198,7 +222,7 @@ var STHash128 = exports.Hash128 = new SerializedType({ serialize: function (so, val) { var hash = UInt128.from_json(val); if (!hash.is_valid()) { - throw new Error("Invalid Hash128"); + throw new Error('Invalid Hash128'); } serialize_hex(so, hash.to_hex(), true); //noLength = true }, @@ -211,7 +235,7 @@ var STHash256 = exports.Hash256 = new SerializedType({ serialize: function (so, val) { var hash = UInt256.from_json(val); if (!hash.is_valid()) { - throw new Error("Invalid Hash256"); + throw new Error('Invalid Hash256'); } serialize_hex(so, hash.to_hex(), true); //noLength = true }, @@ -224,7 +248,7 @@ var STHash160 = exports.Hash160 = new SerializedType({ serialize: function (so, val) { var hash = UInt160.from_json(val); if (!hash.is_valid()) { - throw new Error("Invalid Hash160"); + throw new Error('Invalid Hash160'); } serialize_hex(so, hash.to_hex(), true); //noLength = true }, @@ -237,23 +261,20 @@ var STHash160 = exports.Hash160 = new SerializedType({ var STCurrency = new SerializedType({ serialize: function (so, val) { var currency = val.to_json().toUpperCase(); + + if (!isCurrencyString(currency)) { + throw new Error('Tried to serialize invalid/unimplemented currency type.'); + } + if (currency === 'XRP') { serialize_hex(so, UInt160.HEX_ZERO, true); - } else if (typeof currency === 'string'&& currency.length === 3) { + } else { var currencyCode = currency.toUpperCase(); var currencyData = utils.arraySet(20, 0); - - if (!/^[A-Z]{3}$/.test(currencyCode)) { - throw new Error('Invalid currency code'); - } - currencyData[12] = currencyCode.charCodeAt(0) & 0xff; currencyData[13] = currencyCode.charCodeAt(1) & 0xff; currencyData[14] = currencyCode.charCodeAt(2) & 0xff; - so.append(currencyData); - } else { - throw new Error('Tried to serialize invalid/unimplemented currency type.'); } }, parse: function (so) { @@ -263,7 +284,7 @@ var STCurrency = new SerializedType({ // UInt160 value and consider it valid. But it doesn't, so for the // deserialization to be usable, we need to allow invalid results for now. //if (!currency.is_valid()) { - // throw new Error("Invalid currency: "+convert_bytes_to_hex(bytes)); + // throw new Error('Invalid currency: '+convert_bytes_to_hex(bytes)); //} return currency; } @@ -273,11 +294,12 @@ var STAmount = exports.Amount = new SerializedType({ serialize: function (so, val) { var amount = Amount.from_json(val); if (!amount.is_valid()) { - throw new Error("Not a valid Amount object."); + throw new Error('Not a valid Amount object.'); } // Amount (64-bit integer) var valueBytes = utils.arraySet(8, 0); + if (amount.is_native()) { var valueHex = amount._value.toString(16); @@ -287,7 +309,7 @@ var STAmount = exports.Amount = new SerializedType({ } while (valueHex.length < 16) { - valueHex = "0" + valueHex; + valueHex = '0' + valueHex; } valueBytes = bytes.fromBits(hex.toBits(valueHex)); @@ -346,7 +368,7 @@ var STAmount = exports.Amount = new SerializedType({ var value = new BigInteger(mantissa_bytes, 256); if (value.equals(BigInteger.ZERO) && !is_zero ) { - throw new Error("Invalid zero representation"); + throw new Error('Invalid zero representation'); } amount._value = value; @@ -371,7 +393,7 @@ var STVL = exports.VariableLength = new SerializedType({ if (typeof val === 'string') { serialize_hex(so, val); } else { - throw new Error("Unknown datatype."); + throw new Error('Unknown datatype.'); } }, parse: function (so) { @@ -384,7 +406,7 @@ var STAccount = exports.Account = new SerializedType({ serialize: function (so, val) { var account = UInt160.from_json(val); if (!account.is_valid()) { - throw new Error("Invalid account!"); + throw new Error('Invalid account!'); } serialize_hex(so, account.to_hex()); }, @@ -392,13 +414,14 @@ var STAccount = exports.Account = new SerializedType({ var len = this.parse_varint(so); if (len !== 20) { - throw new Error("Non-standard-length account ID"); + throw new Error('Non-standard-length account ID'); } var result = UInt160.from_bytes(so.read(len)); - //console.log("PARSED 160:", result.to_json()); + + //console.log('PARSED 160:', result.to_json()); if (false && !result.is_valid()) { - throw new Error("Invalid Account"); + throw new Error('Invalid Account'); } return result; @@ -420,12 +443,12 @@ var STPathSet = exports.PathSet = new SerializedType({ for (var j=0, l2=val[i].length; j= 16) { @@ -553,41 +576,35 @@ function serialize_whatever(so, field_name, value) { } //Take the serialized object, figure out what type/field it is, and return the parsing of that. -exports.parse_whatever = parse_whatever; -function parse_whatever(so) { +exports.parse = exports.parse_whatever = parse; + +function parse(so) { var tag_byte = so.read(1)[0]; var type_bits = tag_byte >> 4; - var field_bits = tag_byte & 0x0f; - var type; - var field_name; if (type_bits === 0) { type_bits = so.read(1)[0]; } - type = TYPES_MAP[type_bits]; + var type = TYPES_MAP[type_bits]; - if (typeof type === 'undefined') { - throw Error("Unknown type: "+type_bits); - } else { - if (field_bits === 0) { - field_name = FIELDS_MAP[type_bits][so.read(1)[0]]; - } else { - field_name = FIELDS_MAP[type_bits][field_bits]; - } - if (typeof field_name === 'undefined') { - throw Error("Unknown field " + tag_byte); - } else { - return [field_name, type.parse(so)]; //key, value - } - } + assert(type, 'Unknown type: ' + type_bits); + + var field_bits = tag_byte & 0x0f; + var field_name = (field_bits === 0) + ? field_name = FIELDS_MAP[type_bits][so.read(1)[0]] + : field_name = FIELDS_MAP[type_bits][field_bits]; + + assert(field_name, 'Unknown field: ' + tag_byte); + + return [ field_name, type.parse(so) ]; //key, value }; var STObject = exports.Object = new SerializedType({ serialize: function (so, val) { var keys = Object.keys(val); for (var i=0; i