var binformat = require('./binformat'), sjcl = require('../../../build/sjcl'), extend = require('extend'), stypes = require('./serializedtypes'); var UInt256 = require('./uint256').UInt256; var SerializedObject = function (buf) { if (Array.isArray(buf) || (Buffer && Buffer.isBuffer(buf)) ) { this.buffer = buf; } else if ("string" === typeof buf) { this.buffer = sjcl.codec.bytes.fromBits(sjcl.codec.hex.toBits(buf)); } else if (!buf) { this.buffer = []; } else { throw new Error("Invalid buffer passed."); } this.pointer = 0; }; SerializedObject.from_json = function (obj) { var typedef; var so = new SerializedObject(); // Create a copy of the object so we don't modify it obj = extend({}, obj); if ("number" === typeof obj.TransactionType) { obj.TransactionType = SerializedObject.lookup_type_tx(obj.TransactionType); if (!obj.TransactionType) { throw new Error("Transaction type ID is invalid."); } } if ("string" === typeof obj.TransactionType) { typedef = binformat.tx[obj.TransactionType].slice(); obj.TransactionType = typedef.shift(); } else if ("undefined" !== typeof obj.LedgerEntryType) { // XXX: TODO throw new Error("Ledger entry binary format not yet implemented."); } else throw new Error("Object to be serialized must contain either " + "TransactionType or LedgerEntryType."); so.serialize(typedef, obj); return so; }; SerializedObject.prototype.append = function (bytes) { this.buffer = this.buffer.concat(bytes); this.pointer += bytes.length; }; SerializedObject.prototype.resetPointer = function () { this.pointer = 0; }; /* SerializedObject.prototype.read = function (numberOfBytes) { var start = this.pointer; var end = start+numberOfBytes; if (end > this.buffer.length) { throw new Error("There aren't that many bytes left to read."); } else { var result = this.buffer.slice(start,end); this.pointer = end; return result; } }; */ var readOrPeek = function (advance) { return function(numberOfBytes) { var start = this.pointer; var end = start+numberOfBytes; if (end > this.buffer.length) { throw new Error("There aren't that many bytes left."); } else { var result = this.buffer.slice(start,end); if (advance) {this.pointer = end;} return result; } } } SerializedObject.prototype.read = readOrPeek(true); SerializedObject.prototype.peek = readOrPeek(false); SerializedObject.prototype.to_bits = function () { return sjcl.codec.bytes.toBits(this.buffer); }; SerializedObject.prototype.to_hex = function () { return sjcl.codec.hex.fromBits(this.to_bits()).toUpperCase(); }; var TRANSACTION_TYPES = { 0:"Payment", 3:"AccountSet", 5:"SetRegularKey", 7:"OfferCreate", 8:"OfferCancel", 9:"Contract", 10:"RemoveContract", 20:"TrustSet", 100:"EnableFeature", 101:"SetFee" }; SerializedObject.prototype.to_json = function() { var old_pointer = this.pointer; this.resetPointer(); var output = {}; while (true) { var key_and_value = stypes.parse_whatever(this); var key = key_and_value[0]; var value = key_and_value[1]; output[key] = jsonify_structure(value,key); if (this.pointer == this.buffer.length) { break; } else if (this.pointer > this.buffer.length) { console.log("WARNING: Buffer length exceeded during SerializedObject.to_json"); break; } } this.pointer = old_pointer; return output; } function jsonify_structure(thing,field_name) { var output; var typeof_thing = typeof thing; if ("number" === typeof thing) { //Special codes if (field_name) { if (field_name === "LedgerEntryType") { output = thing; //TODO: Do we have special codes for LedgerEntryType? } else if (field_name === "TransactionType") { output = TRANSACTION_TYPES[thing] || thing; } else { output = thing; } } else { output = thing; } } else if ("object" === typeof thing && "function" === typeof thing.to_json) { output = thing.to_json(); } else if (Array.isArray(thing)) { //console.log("here2"); //iterate over array [] output = []; for (var i=0; i< thing.length; i++) { output.push(jsonify_structure(thing[i])); } } else if ("object" === typeof thing) { //console.log("here1", thing); //iterate over object {} output = {}; var keys = Object.keys(thing); for (var i=0; i 0xf) buffer.push(type_id & 0xff); else buffer[0] += (type_id & 0xf) << 4; if (field_id > 0xf) buffer.push(field_id & 0xff); else buffer[0] += field_id & 0xf; return buffer; }; function sort_field_compare(a, b) { // Sort by type id first, then by field id return a[3].id !== b[3].id ? a[3].id - b[3].id : a[2] - b[2]; }; SerializedObject._sort_typedef = function (typedef) { return typedef.sort(sort_field_compare); }; SerializedObject.lookup_type_tx = function (id) { for (var i in binformat.tx) { if (!binformat.tx.hasOwnProperty(i)) continue; if (binformat.tx[i][0] === id) { return i; } } return null; }; exports.SerializedObject = SerializedObject;