qpid-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From r..@apache.org
Subject [10/51] [abbrv] qpid-proton git commit: Implemented the remainder of the codec methods and ported the codec unit test suite to test it all
Date Fri, 28 Nov 2014 13:49:48 GMT
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6aed8542/proton-c/bindings/javascript/binding.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/binding.js b/proton-c/bindings/javascript/binding.js
index 43634d4..08aeb3e 100644
--- a/proton-c/bindings/javascript/binding.js
+++ b/proton-c/bindings/javascript/binding.js
@@ -37,15 +37,16 @@
  * from minifying e.g. <pre>Module['Messenger'] = ...</pre>
  * Exported Objects can be used in client code using the appropriate namespace:
  * <pre>
- * proton = require("proton.js");
+ * proton = require('proton.js');
  * var messenger = new proton.Messenger();
  * var message = new proton.Message();
  * </pre>
  * @namespace proton
  */
+
 var Module = {
     // Prevent emscripten runtime exiting, we will be enabling network callbacks.
-    'noExitRuntime' : true
+    'noExitRuntime' : true,
 };
 
 /*****************************************************************************/
@@ -790,7 +791,7 @@ Module['Message'] = function() { // Message Constructor.
      * Application defined Message properties.
      * @type map
      */
-    this['properties'] = null;
+    this['properties'] = {};
 
     /**
      * Message body.
@@ -835,32 +836,35 @@ _Message_._check = function(code) {
  * Encode the Message prior to sending on the wire.
  */
 _Message_._preEncode = function() {
-    if (this.instructions) {
+    // A Message Object may be reused so we create new Data instances and clear
+    // the state for them each time put() gets called.
+    var inst = new Data(_pn_message_instructions(this._message));
+    var ann = new Data(_pn_message_annotations(this._message));
+    var props = new Data(_pn_message_properties(this._message));
+    var body = new Data(_pn_message_body(this._message));
+
+    inst.clear();
+    if (this['instructions']) {
 console.log("Encoding instructions");
-        var inst = new Data(_pn_message_instructions(this._message));
-        inst.clear();
-        inst.putObject(this.instructions);
+        inst['putObject'](this['instructions']);
     }
 
-    if (this.annotations) {
+    ann.clear();
+    if (this['annotations']) {
 console.log("Encoding annotations");
-        var ann = new Data(_pn_message_annotations(this._message));
-        ann.clear();
-        ann.putObject(this.annotations);
+        ann['putObject'](this['annotations']);
     }
 
-    if (this.properties) {
+    props.clear();
+    if (this['properties']) {
 console.log("Encoding properties");
-        var props = new Data(_pn_message_properties(this._message));
-        props.clear();
-        props.putObject(this.properties);
+        props['putObject'](this['properties']);
     }
 
-    if (this.body != null) {
+    body.clear();
+    if (this['body']) {
 console.log("Encoding body");
-        var body = new Data(_pn_message_body(this._message));
-        body.clear();
-        body.putObject(this.body);
+        body['putObject'](this['body']);
     }
 };
 
@@ -874,27 +878,27 @@ _Message_._postDecode = function() {
     var body = new Data(_pn_message_body(this._message));
 
     if (inst.next()) {
-        this.instructions = inst.getObject();
+        this['instructions'] = inst['getObject']();
     } else {
-        this.instructions = {};
+        this['instructions'] = {};
     }
 
     if (ann.next()) {
-        this.annotations = ann.getObject();
+        this['annotations'] = ann['getObject']();
     } else {
-        this.annotations = {};
+        this['annotations'] = {};
     }
 
     if (props.next()) {
-        this.properties = props.getObject();
+        this['properties'] = props['getObject']();
     } else {
-        this.properties = {};
+        this['properties'] = {};
     }
 
     if (body.next()) {
-        this.body = body.getObject();
+        this['body'] = body['getObject']();
     } else {
-        this.body = null;
+        this['body'] = null;
     }
 };
 
@@ -933,7 +937,7 @@ _Message_['getError'] = function() {
 /**
  * @method getAddress
  * @memberof! proton.Message#
- * @return {string} the address of the Message.
+ * @returns {string} the address of the Message.
  */
 _Message_['getAddress'] = function() {
     return Pointer_stringify(_pn_message_get_address(this._message));
@@ -1014,13 +1018,25 @@ _Message_['setSubject'] = function(subject) {
  * sibling then one will be added. The put* methods always set the added/modified
  * node to the current node. The get* methods read the value of the current node
  * and do not change which node is current.
- * @constructor proton.Data                                                                
+ * @constructor proton.Data
+ * @param {number} data an optional pointer to a pn_data_t instance. If supplied
+ *        the underlying data is "owned" by another object (for example a Message)
+ *        and that object is assumed to be responsible for freeing the data if
+ *        necessary. If no data is supplied then the Data is stand-alone and the
+ *        client application is responsible for freeing the underlying data via
+ *        a call to free().
  */
 Module['Data'] = function(data) { // Data Constructor.
-    this._data = data;
-
     if (!data) {
-        console.log("Warning Data created with null data");
+        this._data = _pn_data(16); // Default capacity is 16
+        this['free'] = function() {
+            _pn_data_free(this._data);
+            // Set free to a null function to prevent possibility of a "double free".
+            this['free'] = function() {};
+        };
+    } else {
+        this._data = data;
+        this['free'] = function() {};
     }
 };
 
@@ -1030,62 +1046,89 @@ var Data = Module['Data'];
 // Expose prototype as a variable to make method declarations less verbose.
 var _Data_ = Data.prototype;
 
+// ************************** Class properties ********************************
+
+Data['NULL']       = 1;
+Data['BOOL']       = 2;
+Data['UBYTE']      = 3;
+Data['BYTE']       = 4;
+Data['USHORT']     = 5;
+Data['SHORT']      = 6;
+Data['UINT']       = 7;
+Data['INT']        = 8;
+Data['CHAR']       = 9;
+Data['ULONG']      = 10;
+Data['LONG']       = 11;
+Data['TIMESTAMP']  = 12;
+Data['FLOAT']      = 13;
+Data['DOUBLE']     = 14;
+Data['DECIMAL32']  = 15;
+Data['DECIMAL64']  = 16;
+Data['DECIMAL128'] = 17;
+Data['UUID']       = 18;
+Data['BINARY']     = 19;
+Data['STRING']     = 20;
+Data['SYMBOL']     = 21;
+Data['DESCRIBED']  = 22;
+Data['ARRAY']      = 23;
+Data['LIST']       = 24;
+Data['MAP']        = 25;
+
 /**
  * Look-up table mapping proton-c types to the accessor method used to
  * deserialise the type. N.B. this is a simple Array and not a map because the
  * types that we get back from pn_data_type are integers from the pn_type_t enum.
- * @property {Array<String>} GetMappings
+ * @property {Array<String>} TypeNames
  * @memberof! proton.Data
  */
-Data.GetMappings = [
-    'getNull',            // 0
-    'getNull',            // PN_NULL = 1
-    'getBoolean',         // PN_BOOL = 2
-    'getUnsignedByte',    // PN_UBYTE = 3
-    'getByte',            // PN_BYTE = 4
-    'getUnsignedShort',   // PN_USHORT = 5
-    'getShort',           // PN_SHORT = 6
-    'getUnsignedInteger', // PN_UINT = 7
-    'getInteger',         // PN_INT = 8
-    'getChar',            // PN_CHAR = 9
-    'getUnsignedLong',    // PN_ULONG = 10
-    'getLong',            // PN_LONG = 11
-    'getTimestamp',       // PN_TIMESTAMP = 12
-    'getFloat',           // PN_FLOAT = 13
-    'getDouble',          // PN_DOUBLE = 14
-    'getDecimal32',       // PN_DECIMAL32 = 15
-    'getDecimal64',       // PN_DECIMAL64 = 16
-    'getDecimal128',      // PN_DECIMAL128 = 17
-    'getUUID',            // PN_UUID = 18
-    'getBinary',          // PN_BINARY = 19
-    'getString',          // PN_STRING = 20
-    'getSymbol',          // PN_SYMBOL = 21
-    'getDescribed',       // PN_DESCRIBED = 22
-    'getArray',           // PN_ARRAY = 23
-    'getJSArray',         // PN_LIST = 24
-    'getDictionary'       // PN_MAP = 25
+Data['TypeNames'] = [
+    'NULL',       // 0
+    'NULL',       // PN_NULL       = 1
+    'BOOL',       // PN_BOOL       = 2
+    'UBYTE',      // PN_UBYTE      = 3
+    'BYTE',       // PN_BYTE       = 4
+    'USHORT',     // PN_USHORT     = 5
+    'SHORT',      // PN_SHORT      = 6
+    'UINT',       // PN_UINT       = 7
+    'INT',        // PN_INT        = 8
+    'CHAR',       // PN_CHAR       = 9
+    'ULONG',      // PN_ULONG      = 10
+    'LONG',       // PN_LONG       = 11
+    'TIMESTAMP',  // PN_TIMESTAMP  = 12
+    'FLOAT',      // PN_FLOAT      = 13
+    'DOUBLE',     // PN_DOUBLE     = 14
+    'DECIMAL32',  // PN_DECIMAL32  = 15
+    'DECIMAL64',  // PN_DECIMAL64  = 16
+    'DECIMAL128', // PN_DECIMAL128 = 17
+    'UUID',       // PN_UUID       = 18
+    'BINARY',     // PN_BINARY     = 19
+    'STRING',     // PN_STRING     = 20
+    'SYMBOL',     // PN_SYMBOL     = 21
+    'DESCRIBED',  // PN_DESCRIBED  = 22
+    'ARRAY',      // PN_ARRAY      = 23
+    'LIST',       // PN_LIST       = 24
+    'MAP'         // PN_MAP        = 25
 ];
 
 // *************************** Class methods **********************************
 
 /**
- * Test if a given Object is an Array.
+ * Test if a given Object is a JavaScript Array.
  * @method isArray
  * @memberof! proton.Data
  * @param {object} o the Object that we wish to test.
- * @returns {boolean} true iff the Object is an Array.
+ * @returns {boolean} true iff the Object is a JavaScript Array.
  */
 Data.isArray = Array.isArray || function(o) {
-console.log("Data.isArray");
     return Object.prototype.toString.call(o) === '[object Array]';
 };
 
 /**
- * Test if a given Object is a Number.
+ * Test if a given Object is a JavaScript Number.
  * @method isNumber
  * @memberof! proton.Data
  * @param {object} o the Object that we wish to test.
- * @returns {boolean} true iff the Object is a Number.
+ * @returns {boolean} true iff the Object is a JavaScript Number.
  */
 Data.isNumber = function(o) {
     return typeof o === 'number' || 
@@ -1093,11 +1136,11 @@ Data.isNumber = function(o) {
 };
 
 /**
- * Test if a given Object is a String.
+ * Test if a given Object is a JavaScript String.
  * @method isString
  * @memberof! proton.Data
  * @param {object} o the Object that we wish to test.
- * @returns {boolean} true iff the Object is a String.
+ * @returns {boolean} true iff the Object is a JavaScript String.
  */
 Data.isString = function(o) {
     return typeof o === 'string' ||
@@ -1105,11 +1148,11 @@ Data.isString = function(o) {
 };
 
 /**
- * Test if a given Object is a Boolean.
+ * Test if a given Object is a JavaScript Boolean.
  * @method isBoolean
  * @memberof! proton.Data
  * @param {object} o the Object that we wish to test.
- * @returns {boolean} true iff the Object is a Boolean.
+ * @returns {boolean} true iff the Object is a JavaScript Boolean.
  */
 Data.isBoolean = function(o) {
     return typeof o === 'boolean' ||
@@ -1118,20 +1161,20 @@ Data.isBoolean = function(o) {
 
 // **************************** Inner Classes *********************************
 
-// --------------------------- proton.Data.UUID -------------------------------
+// --------------------------- proton.Data.Uuid -------------------------------
 /**
- * Create a proton.Data.UUID which is a type 4 UUID.
+ * Create a proton.Data.Uuid which is a type 4 UUID.
  * @classdesc
  * This class represents a type 4 UUID, wich may use crypto libraries to generate
  * the UUID if supported by the platform (e.g. node.js or a modern browser)
- * @constructor proton.Data.UUID
+ * @constructor proton.Data.Uuid
  * @param u a UUID. If null a type 4 UUID is generated wich may use crypto if
  *        supported by the platform. If u is an emscripten "pointer" we copy the
  *        data from that. If u is a JavaScript Array we use it as-is. If u is a
  *        String then we try to parse that as a UUID.
  * @property {Array} uuid is the compact array form of the UUID.
  */
-Data['UUID'] = function(u) { // Data.UUID Constructor.
+Data['Uuid'] = function(u) { // Data.Uuid Constructor.
     // Helper to copy from emscriptem allocated storage into JavaScript Array.
     function _p2a(p) {
         var uuid = new Array(16);
@@ -1167,13 +1210,14 @@ Data['UUID'] = function(u) { // Data.UUID Constructor.
 };
 
 /**
+ * Returns the string representation of the proton.Data.Uuid.
  * @method toString
- * @memberof! proton.Data.UUID#
+ * @memberof! proton.Data.Uuid#
  * @returns {string} the String
  *          /[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}/
- *          form of a {@link proton.Data.UUID}.
+ *          form of a {@link proton.Data.Uuid}.
  */
-Data['UUID'].prototype.toString = function() {
+Data['Uuid'].prototype.toString = Data['Uuid'].prototype.valueOf = function() {
     if (!this.string) { // Check if we've cached the string version.
         var i = 0;
         var uu = this['uuid'];
@@ -1189,17 +1233,16 @@ Data['UUID'].prototype.toString = function() {
 };
 
 /**
- * Compare two instances of proton.Data.UUID for equality.
+ * Compare two instances of proton.Data.Uuid for equality.
  * @method equals
- * @memberof! proton.Data.UUID#
- * @param {proton.Data.UUID} rhs the instance we wish to compare this instance with.
+ * @memberof! proton.Data.Uuid#
+ * @param {proton.Data.Uuid} rhs the instance we wish to compare this instance with.
  * @returns {boolean} true iff the two compared instances are equal.
  */
-Data['UUID'].prototype['equals'] = function(rhs) {
+Data['Uuid'].prototype['equals'] = function(rhs) {
     return this.toString() === rhs.toString();
 };
 
-
 // ---------------------------- proton.Data.Symbol ---------------------------- 
 /**
  * Create a proton.Data.Symbol.
@@ -1212,7 +1255,6 @@ Data['UUID'].prototype['equals'] = function(rhs) {
  */
 Data['Symbol'] = function(s) { // Data.Symbol Constructor.
     this.value = s;
-    this.length = this.value.length;
 };
 
 /**
@@ -1235,54 +1277,178 @@ Data['Symbol'].prototype['equals'] = function(rhs) {
     return this.toString() === rhs.toString();
 };
 
+// ---------------------------- proton.Data.Described ---------------------------- 
+/**
+ * Create a proton.Data.Described.
+ * @classdesc
+ * This class represents an AMQP Described.
+ * @constructor proton.Data.Described
+ * @param {object} value the value of the described type.
+ * @param {string} descriptor an optional string describing the type.
+ * @property {object} value the actual value of the described type.
+ * @property {string} descriptor a string describing the type.
+ */
+Data['Described'] = function(value, descriptor) { // Data.Described Constructor.
+    this['value'] = value;
+    this['descriptor'] = descriptor;
+};
+
+/**
+ * @method toString
+ * @memberof! proton.Data.Described#
+ * @returns {string} the String form of a {@link proton.Data.Described}.
+ */
+Data['Described'].prototype.toString = function() {
+    return 'Described(' + this['value'] + ', ' + this['descriptor'] + ')';
+};
+
+/**
+ * @method valueOf
+ * @memberof! proton.Data.Described#
+ * @returns {object} the value of the {@link proton.Data.Described}.
+ */
+Data['Described'].prototype.valueOf = function() {
+    return this['value'];
+};
+
+/**
+ * Compare two instances of proton.Data.Described for equality.
+ * @method equals
+ * @memberof! proton.Data.Described#
+ * @param {proton.Data.Described} rhs the instance we wish to compare this instance with.
+ * @returns {boolean} true iff the two compared instances are equal.
+ */
+Data['Described'].prototype['equals'] = function(rhs) {
+    if (rhs instanceof Data['Described']) {
+        return ((this['descriptor'] === rhs['descriptor']) && (this['value'] === rhs['value']));
+    } else {
+        return false;
+    }
+};
+
+// ---------------------------- proton.Data.Array ---------------------------- 
+/**
+ * TODO make this behave more like a native JavaScript Array: http://www.bennadel.com/blog/2292-extending-javascript-arrays-while-keeping-native-bracket-notation-functionality.htm
+ * Create a proton.Data.Array.
+ * @classdesc
+ * This class represents an AMQP Array.
+ * @constructor proton.Data.Array
+ * @param {{string|number)} type the type of the Number either as a string or number.
+ *        Stored internally as a string corresponding to one of the TypeNames.       
+ * @param {Array|TypedArray} elements the Native JavaScript Array or TypedArray that we wish to serialise.
+ * @param {object} descriptor an optional object describing the type.
+ */
+Data['Array'] = function(type, elements, descriptor) { // Data.Array Constructor.
+    // This block caters for an empty Array or a Described empty Array.
+    if (arguments.length < 2) {
+        descriptor = type;
+        type = 'NULL';
+        elements = [];
+    }
+
+    this['type']  = (typeof type === 'number') ? Data['TypeNames'][type] : type;
+    this['elements'] = elements;
+    this['descriptor'] = descriptor;
+};
+
+/**
+ * @method toString
+ * @memberof! proton.Data.Array#
+ * @returns {string} the String form of a {@link proton.Data.Array}.
+ */
+Data['Array'].prototype.toString = function() {
+    var descriptor = (this['descriptor'] == null) ? '' : ':' + this['descriptor'];
+    return this['type'] + 'Array' + descriptor + '[' + this['elements'] + ']';
+};
+
+/**
+ * @method valueOf
+ * @memberof! proton.Data.Array#
+ * @returns {Array} the elements of the {@link proton.Data.Array}.
+ */
+Data['Array'].prototype.valueOf = function() {
+    return this['elements'];
+};
+
+/**
+ * Compare two instances of proton.Data.Array for equality. N.B. this method
+ * compares the value of every Array element so its performance is O(n).
+ * @method equals
+ * @memberof! proton.Data.Array#
+ * @param {proton.Data.Array} rhs the instance we wish to compare this instance with.
+ * @returns {boolean} true iff the two compared instances are equal.
+ */
+Data['Array'].prototype['equals'] = function(rhs) {
+    if (rhs instanceof Data['Array'] &&
+        // Check the string value of the descriptors.
+        (('' + this['descriptor']) === ('' + rhs['descriptor'])) &&
+        (this['type'] === rhs['type'])) {
+        var elements = this['elements'];
+        var relements = rhs['elements'];
+        var length = elements.length;
+        if (length === relements.length) {
+            for (var i = 0; i < length; i++) {
+                if (elements[i].valueOf() !== relements[i].valueOf()) {
+                    return false;
+                }
+            }
+            return true;
+        } else {
+            return false;
+        }
+    } else {
+        return false;
+    }
+};
+
 // ---------------------- JavaScript Number Extensions ------------------------ 
 
-Number.prototype['asUnsignedByte'] = function() {
-    return new Data.TypedNumber('UnsignedByte', this);
+Number.prototype['ubyte'] = function() {
+    return new Data.TypedNumber('UBYTE', this);
 };
 
-Number.prototype['asByte'] = function() {
-    return new Data.TypedNumber('Byte', this);
+Number.prototype['byte'] = function() {
+    return new Data.TypedNumber('BYTE', this);
 };
 
-Number.prototype['asUnsignedShort'] = function() {
-    return new Data.TypedNumber('UnsignedShort', this);
+Number.prototype['ushort'] = function() {
+    return new Data.TypedNumber('USHORT', this);
 };
 
-Number.prototype['asShort'] = function() {
-    return new Data.TypedNumber('Short', this);
+Number.prototype['short'] = function() {
+    return new Data.TypedNumber('SHORT', this);
 };
 
-Number.prototype['asUnsignedInteger'] = function() {
-    return new Data.TypedNumber('UnsignedInteger', this);
+Number.prototype['uint'] = function() {
+    return new Data.TypedNumber('UINT', this);
 };
 
-Number.prototype['asInteger'] = function() {
-    return new Data.TypedNumber('Integer', this);
+Number.prototype['int'] = function() {
+    return new Data.TypedNumber('INT', this);
 };
 
-Number.prototype['asUnsignedLong'] = function() {
-    return new Data.TypedNumber('UnsignedLong', this);
+Number.prototype['ulong'] = function() {
+    return new Data.TypedNumber('ULONG', this);
 };
 
-Number.prototype['asLong'] = function() {
-    return new Data.TypedNumber('Long', this);
+Number.prototype['long'] = function() {
+    return new Data.TypedNumber('LONG', this);
 };
 
-Number.prototype['asFloat'] = function() {
-    return new Data.TypedNumber('Float', this);
+Number.prototype['float'] = function() {
+    return new Data.TypedNumber('FLOAT', this);
 };
 
-Number.prototype['asDouble'] = function() {
-    return new Data.TypedNumber('Double', this);
+Number.prototype['double'] = function() {
+    return new Data.TypedNumber('DOUBLE', this);
 };
 
-Number.prototype['asChar'] = function() {
-    return new Data.TypedNumber('Char', this);
+Number.prototype['char'] = function() {
+    return new Data.TypedNumber('CHAR', this);
 };
 
-String.prototype['asChar'] = function() {
-    return new Data.TypedNumber('Char', this.charCodeAt(0));
+String.prototype['char'] = function() {
+    return new Data.TypedNumber('CHAR', this.charCodeAt(0));
 };
 
 // ------------------------- proton.Data.TypedNumber -------------------------- 
@@ -1292,21 +1458,30 @@ String.prototype['asChar'] = function() {
  * This class is a simple wrapper class that allows a "type" to be recorded for
  * a number. The idea is that the JavaScript Number class is extended with extra
  * methods to allow numbers to be "modified" to TypedNumbers, so for example
- * 1.0.asFloat() would modify 1.0 by returning a TypedNumber with type = Float
+ * 1.0.float() would modify 1.0 by returning a TypedNumber with type = FLOAT
  * and value = 1. The strings used for type correspond to the names of the Data
- * put* methods e.g. UnsignedByte, Byte, UnsignedShort, Short, UnsignedInteger,
- * Integer, UnsignedLong, Long, Float, Double, Char so that the correct method
- * to call can be easily derived from the TypedNumber's type.
+ * put* methods e.g. UBYTE, BYTE, USHORT, SHORT, UINT, INT, ULONG, LONG, FLOAT,
+ * DOUBLE, CHAR so that the correct method to call can be derived from the type.
  * @constructor proton.Data.TypedNumber
- * @param {string} type the type of the Number.
- * @param {number} value the most significant word.
+ * @param {(string|number)} type the type of the Number either as a string or number.
+ *        Stored internally as a string corresponding to one of the TypeNames.
+ * @param {number} value the value of the Number.
  */
 // Use dot notation as it is a "protected" inner class not exported from the closure.
 Data.TypedNumber = function(type, value) { // Data.TypedNumber Constructor.
-    this.type  = type;
+    this.type  = (typeof type === 'number') ? Data['TypeNames'][type] : type;
     this.value = value;
 };
 
+/**
+ * @method toString
+ * @memberof! proton.Data.TypedNumber#
+ * @returns {string} the String form of a {@link proton.Data.TypedNumber}.
+ */
+Data.TypedNumber.prototype.toString = Data.TypedNumber.prototype.valueOf = function() {
+    return +this.value;
+};
+
 // ----------------------------- proton.Data.Long ----------------------------- 
 /**
  * Create a proton.Data.Long.
@@ -1345,7 +1520,7 @@ Data.Long.fromNumber = function(value) {
     if (isNaN(value) || !isFinite(value)) {
         return Data.Long.ZERO;
     } else if (value <= -Data.Long.TWO_PWR_63_DBL_) {
-        return Data.MIN_VALUE;
+        return Data.Long.MIN_VALUE;
     } else if (value + 1 >= Data.Long.TWO_PWR_63_DBL_) {
         return Data.Long.MAX_VALUE;
     } else if (value < 0) {
@@ -1470,71 +1645,93 @@ Data.Long.prototype.toNumber = function() {
  * @returns {string} the String form of a {@link proton.Data.Long}.
  */
 Data.Long.prototype.toString = function() {
-    return this.high + ":" + this.getLowBitsUnsigned();
+    return this.high + ':' + this.getLowBitsUnsigned();
 };
 
 // ---------------------------- proton.Data.Binary ----------------------------
 /**
- * Create a proton.Data.Binary. This constructor takes one or two parameters,
- * size specifies the size in bytes of the Binary buffer, start is a pointer
- * to the data in an internal data store. If start is not specified then size
- * bytes will be allocated in the internal data store and start will point to
- * the start of that block of data.
+ * Create a proton.Data.Binary. This constructor takes one or two parameters.
+ * The first parameter may serve different purposes depending on its type;
+ * If value is a number then it represents the size of the Binary data buffer,
+ * if it is a string then we copy the string to the buffer, if it is an Array
+ * or a TypedArray then we copy the data to the buffer. The optional second
+ * parameter is a pointer to the data in an internal data store. If start is
+ * not specified then the number of bytes specified in the first parameter
+ * will be allocated in the internal data store and start will point to the
+ * start of that block of data.
  * @classdesc
  * This class represents an AMQP Binary type. This class allows us to create and
  * use raw binary data and map it efficiently between JavaScript client code and
- * the underlying implementation, where all data is managed on a virtual heap.
+ * the underlying implementation, where all data is managed on a "virtual heap".
+ * <p>
+ * Client applications should generally not have to care about memory management
+ * as, for most common use cases, client applications would "transfer ownership"
+ * to a "container" which would then "own" the underlying data and free the data
+ * held by the {@link proton.Data.Binary}.
  * <p>
- * Client applications should not have to care about memory management. A client
- * should create a {@link proton.Data.Binary} specifying the required size then
- * call getBuffer to access the underlying Uint8Array. When {@link proton.Data.putBinary}
- * is called ownership of the bytes transfers from the Binary to the Data and
- * putBinary can then safely call free. Conversely when receiving data a Binary
- * may be created by {@link proton.Data.getBinary} in this case the Binary is
- * simply a "view" onto the bytes owned by the Data instance. A client application
- * can safely access the bytes from the view, but if it wishes to use the bytes
- * beyond the scope of the Data instance (for example after the next
- * {@link proton.Messenger.get} call then the client must explicitly *copy* the
- * bytes into a new buffer via copyBuffer().
+ * As an example one common use-case would be where client application creates a
+ * {@link proton.Data.Binary} specifying the required size. It would usually then
+ * call getBuffer() to access the underlying Uint8Array. At this point the client
+ * "owns" the data and so would have to call free() if it did nothing more with
+ * the Binary, however when {@link proton.Data.putBINARY} is called the ownership
+ * of the raw data on the virtual heap transfers from the Binary to the Data and
+ * the client no longer needs to call free() itself. In this case the putBINARY()
+ * call transfers ownership and can then safely call free() on the Binary.
+ * <p>
+ * Conversely a common use-case when receiving data is where a Binary may be
+ * created by {@link proton.Data.getBINARY}. In this case the Binary is simply a
+ * "view" onto the bytes owned by the Data instance. A client application can
+ * safely access the bytes from the view, but if it wishes to use the bytes beyond
+ * the scope of the Data instance (e.g. after the next {@link proton.Messenger.get}
+ * call then the client must explicitly *copy* the bytes into a new buffer, for
+ * example via copyBuffer().
+ * <p>
+ * Most of the {@link proton.Data} methods that take {@link proton.Data.Binary}
+ * as a parameter "consume" the underlying data and take responsibility for
+ * freeing it from the heap {@link proton.Data.putBINARY} {@link proton.Data.decode}.
+ * For the methods that return a {@link proton.Data.Binary} the call to
+ * {@link proton.Data.getBINARY}, which is the most common case, returns a Binary
+ * that has a "view" of the underlying data that is actually owned by the Data
+ * instance and thus doesn't need to be explicitly freed on the Binary. The call
+ * to {@link proton.Data.encode} however returns a Binary that represents a *copy*
+ * of the underlying data, in this case (like a client calling new proton.Data.Binary)
+ * the client takes responsibility for freeing the data, unless of course it is
+ * subsequently passed to a method that will consume the data (putBINARY/decode).
  * @constructor proton.Data.Binary
- * @param {object} data. If data is a number then it represents the size of the
- *        Binary data buffer, if it is a string then we copy the string to the
- *        buffer, if it is an Array or a TypedArray then we copy the data to
- *        the buffer. N.B. although convenient do bear in mind that every method
- *        other than constructing with a size followed by a call to getBuffer will
- *        result in some form of additional data copy.
- * @param {number} start an optional data pointer to the start of the Binary data buffer.
- */
-Data['Binary'] = function(data, start) { // Data.Binary Constructor.
+ * @param {(number|string|Array|TypedArray)} value. If value is a number then it 
+ *        represents the size of the Binary data buffer, if it is a string then
+ *        we copy the string to the buffer, if it is an Array or a TypedArray
+ *        then we copy the data to the buffer. N.B. although convenient do bear
+ *        in mind that using a mechanism other than constructing with a simple
+ *        size will result in some form of additional data copy.
+ * @param {number} start an optional pointer to the start of the Binary data buffer.
+ */
+Data['Binary'] = function(value, start) { // Data.Binary Constructor.
     /**
      * If the start pointer is specified then the underlying binary data is owned
      * by another object, so we set the call to free to be a null function. If
      * the start pointer is not passed then we allocate storage of the specified
      * size on the emscripten heap and set the call to free to free the data from
-     * the emscripten heap. We have made the call to free a protected method that
-     * is only visible within the scope of the binding closure, clients should
-     * not have to call free themselves as the data is either already "owned" by
-     * a Data object or is destined to be passed to a Data object, which will in
-     * turn take responsibility for calling free once it has taken ownership of
-     * the underlying binary data.
+     * the emscripten heap.
      */
-    var size = data;
+    var size = value;
     if (start) {
-        this.free = function() {};
-    } else { // Create Binary from Array, ArrayBuffer or TypedArray
-        if (Data.isArray(data) ||
-            (data instanceof ArrayBuffer) || 
-            (data.buffer && data.buffer instanceof ArrayBuffer)) {
-            data = new Uint8Array(data);
-            size = data.length;
+        this['free'] = function() {};
+    } else { // Create Binary from Array, ArrayBuffer or TypedArray.
+        var hasArrayBuffer = (typeof ArrayBuffer === 'function');
+        if (Data.isArray(value) ||
+            (hasArrayBuffer && value instanceof ArrayBuffer) || 
+            (value.buffer && hasArrayBuffer && value.buffer instanceof ArrayBuffer)) {
+            value = new Uint8Array(value);
+            size = value.length;
             start = _malloc(size); // Allocate storage from emscripten heap.
-            Module.HEAPU8.set(data, start);
-        } else if (Data.isString(data)) { // Create Binary from native string
-            data = unescape(encodeURIComponent(data)); // Create a C-like UTF representation.
-            size = data.length;
+            Module['HEAPU8'].set(value, start); // Copy the data to the emscripten heap.
+        } else if (Data.isString(value)) { // Create Binary from native string
+            value = unescape(encodeURIComponent(value)); // Create a C-like UTF representation.
+            size = value.length;
             start = _malloc(size); // Allocate storage from emscripten heap.
             for (var i = 0; i < size; i++) {
-                setValue(start + i, data.charCodeAt(i), 'i8', 1);
+                setValue(start + i, value.charCodeAt(i), 'i8', 1);
             }
         } else { // Create unpopulated Binary of specified size.
             // If the type is not a number by this point then an unrecognised data
@@ -1542,7 +1739,13 @@ Data['Binary'] = function(data, start) { // Data.Binary Constructor.
             size = Data.isNumber(size) ? size : 0;
             start = _malloc(size); // Allocate storage from emscripten heap.
         }
-        this.free = function() {_free(start);};
+        this['free'] = function() {
+            _free(this.start);
+            this.size = 0;
+            this.start = 0;
+            // Set free to a null function to prevent possibility of a "double free".
+            this['free'] = function() {};
+        };
     }
 
     this.size = size;
@@ -1562,16 +1765,28 @@ Data['Binary'].prototype['getBuffer'] = function() {
 };
 
 /**
- * Explicitly create a *copy* of the underlying binary data and present a Uint8Array
- * view of that copy. This method should be used if a client application wishes to
- * retain an interest in the binary data for longer than it wishes to retain an
- * interest in say a {@link proton.Message}, if that's not the case getBuffer
- * should be used as that avoids the need to copy the data.
- * @method copyBuffer
+ * Explicitly create a *copy* of the Binary copying the underlying binary data too.
+ * @method copy
+ * @param {number} offset an optional offset into the underlying buffer from
+ *        where we want to copy the data, default is zero.
+ * @param {number} n an optional number of bytes to copy, default is this.size - offset.
  * @memberof! proton.Data.Binary#
  */
-Data['Binary'].prototype['copyBuffer'] = function() {
-    return new Uint8Array(new Uint8Array(HEAPU8.buffer, this.start, this.size));
+Data['Binary'].prototype['copy'] = function(offset, n) {
+    offset = offset | 0;
+    n = n ? n : (this.size - offset);
+
+    if (offset >= this.size) {
+        offset = 0;
+        n = 0;
+    } else if ((offset + n) > this.size) {
+        n = this.size - offset; // Clamp length
+    }
+
+    var start = _malloc(n); // Allocate storage from emscripten heap.
+    _memcpy(start, this.start + offset, n); // Copy the raw data to new buffer.
+
+    return new Data['Binary'](n, start);
 };
 
 /**
@@ -1648,9 +1863,8 @@ _Data_['clear'] = function() {
 };
 
 /**
- * Clears current node and sets the parent to the root node.  Clearing the
- * current node sets it _before_ the first node, calling next() will advance
- * to the first node.
+ * Clears current node and sets the parent to the root node.  Clearing the current
+ * node sets it _before_ the first node, calling next() will advance to the first node.
  * @method rewind
  * @memberof! proton.Data#
  */
@@ -1659,9 +1873,8 @@ _Data_['rewind'] = function() {
 };
 
 /**
- * Advances the current node to its next sibling and returns its
- * type. If there is no next sibling the current node remains
- * unchanged and null is returned.
+ * Advances the current node to its next sibling and returns its type. If there
+ * is no next sibling the current node remains unchanged and null is returned.
  * @method next
  * @memberof! proton.Data#
  * @returns {number} the type of the next sibling or null.
@@ -1671,14 +1884,13 @@ _Data_['next'] = function() {
     if (found) {
         return this.type();
     } else {
-        return null;  
+        return null;
     }
 };
 
 /**
- * Advances the current node to its previous sibling and returns its
- * type. If there is no previous sibling the current node remains
- * unchanged and null is returned.
+ * Advances the current node to its previous sibling and returns its type. If there
+ * is no previous sibling the current node remains unchanged and null is returned.
  * @method prev
  * @memberof! proton.Data#
  * @returns {number} the type of the previous sibling or null.
@@ -1693,9 +1905,8 @@ _Data_['prev'] = function() {
 };
 
 /**
- * Sets the parent node to the current node and clears the current node.
- * Clearing the current node sets it _before_ the first child,
- * call next() advances to the first child.
+ * Sets the parent node to the current node and clears the current node. Clearing
+ * the current node sets it _before_ the first child, next() advances to the first child.
  * @method enter
  * @memberof! proton.Data#
  */
@@ -1704,8 +1915,7 @@ _Data_['enter'] = function() {
 };
 
 /**
- * Sets the current node to the parent node and the parent node to
- * its own parent.
+ * Sets the current node to the parent node and the parent node to its own parent.
  * @method exit
  * @memberof! proton.Data#
  */
@@ -1713,10 +1923,13 @@ _Data_['exit'] = function() {
     return (_pn_data_exit(this._data) > 0);
 };
 
-
 /**
+ * Look up a value by name. N.B. Need to use getObject() to retrieve the actual
+ * value after lookup suceeds.
  * @method lookup
  * @memberof! proton.Data#
+ * @param {string} name the name of the property to look up.
+ * @returns {boolean} true iff the lookup succeeded.
  */
 _Data_['lookup'] = function(name) {
     var sp = Runtime.stackSave();
@@ -1725,6 +1938,7 @@ _Data_['lookup'] = function(name) {
     return (lookup > 0);
 };
 
+// TODO document - not quite sure what these are for?
 _Data_['narrow'] = function() {
     _pn_data_narrow(this._data);
 };
@@ -1733,11 +1947,10 @@ _Data_['widen'] = function() {
     _pn_data_widen(this._data);
 };
 
-
 /**
  * @method type
  * @memberof! proton.Data#
- * @returns the type of the current node or null if the type is unknown.
+ * @returns {number} the type of the current node or null if the type is unknown.
  */
 _Data_['type'] = function() {
     var dtype = _pn_data_type(this._data);
@@ -1748,218 +1961,322 @@ _Data_['type'] = function() {
     }
 };
 
-// TODO encode and decode
+/**
+ * Return a Binary representation of the data encoded in AMQP format. N.B. the
+ * returned {@link proton.Data.Binary} "owns" the underlying raw data and is thus
+ * responsible for freeing it or passing it to a method that consumes a Binary
+ * such as {@link proton.Data.decode} or {@link proton.Data.putBINARY}.
+ * @method type
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Binary} a representation of the data encoded in AMQP format.
+ */
+_Data_['encode'] = function() {
+    var size = 1024;
+    while (true) {
+        var bytes = _malloc(size); // Allocate storage from emscripten heap.
+        var cd = _pn_data_encode(this._data, bytes, size);
+
+        if (cd === Module['Error']['OVERFLOW']) {
+            _free(bytes);
+            size *= 2;
+        } else if (cd >= 0) {
+            return new Data['Binary'](cd, bytes);
+        } else {
+            _free(bytes);
+            this._check(cd);
+            return;
+        }
+    }
+};
 
 /**
- * Puts a list value. Elements may be filled by entering the list
+ * Decodes the first value from supplied Binary AMQP data and returns a new
+ * {@link proton.Data.Binary} containing the remainder of the data or null if
+ * all the supplied data has been consumed. N.B. this method "consumes" data
+ * from a {@link proton.Data.Binary} in other words it takes responsibility for
+ * the underlying data and frees the raw data from the Binary.
+ * @method decode
+ * @memberof! proton.Data#
+ * @param {proton.Data.Binary} encoded the AMQP encoded binary data.
+ * @returns {proton.Data.Binary} a Binary contianing the remaining bytes or null
+ *          if all the data has been consumed.
+ */
+_Data_['decode'] = function(encoded) {
+    var start = encoded.start;
+    var size = encoded.size;
+    var consumed = this._check(_pn_data_decode(this._data, start, size));
+
+    size = size - consumed;
+    start = _malloc(size); // Allocate storage from emscripten heap.
+    _memcpy(start, encoded.start + consumed, size);
+
+    encoded['free'](); // Free the original Binary.
+    return size > 0 ? new Data['Binary'](size, start) : null;
+};
+
+/**
+ * Puts a list node. Elements may be filled by entering the list
  * node and putting element values.
  * <pre>
- *  data = new Data();
- *  data.putList();
+ *  var data = new proton.Data();
+ *  data.putLISTNODE();
  *  data.enter();
- *  data.putInt(1);
- *  data.putInt(2);
- *  data.putInt(3);
+ *  data.putINT(1);
+ *  data.putINT(2);
+ *  data.putINT(3);
  *  data.exit();
  * </pre>
- * @method putList
+ * @method putLISTNODE
  * @memberof! proton.Data#
  */
-_Data_['putList'] = function() {
+_Data_['putLISTNODE'] = function() {
     this._check(_pn_data_put_list(this._data));
 };
 
 /**
- * Puts a map value. Elements may be filled by entering the map node
+ * Puts a map node. Elements may be filled by entering the map node
  * and putting alternating key value pairs.
  * <pre>
- *  data = new Data();
- *  data.putMap();
+ *  var data = new proton.Data();
+ *  data.putMAPNODE();
  *  data.enter();
- *  data.putString("key");
- *  data.putString("value");
+ *  data.putSTRING('key');
+ *  data.putSTRING('value');
  *  data.exit();
  * </pre>
- * @method putMap
+ * @method putMAPNODE
  * @memberof! proton.Data#
  */
-_Data_['putMap'] = function() {
+_Data_['putMAPNODE'] = function() {
     this._check(_pn_data_put_map(this._data));
 };
 
-// TODO putArray and putDescribed
+/**
+ * Puts an array node. Elements may be filled by entering the array node and
+ * putting the element values. The values must all be of the specified array
+ * element type. If an array is described then the first child value of the array
+ * is the descriptor and may be of any type.
+ * <pre>
+ *  var data = new proton.Data();
+ *  data.putARRAYNODE(false, proton.Data.INT);
+ *  data.enter();
+ *  data.putINT(1);
+ *  data.putINT(2);
+ *  data.putINT(3);
+ *  data.exit();
+ *
+ *  data.putARRAYNODE(true, proton.Data.DOUBLE);
+ *  data.enter();
+ *  data.putSYMBOL('array-descriptor');
+ *  data.putDOUBLE(1.1);
+ *  data.putDOUBLE(1.2);
+ *  data.putDOUBLE(1.3);
+ *  data.exit();
+ * </pre>
+ * @method putARRAYNODE
+ * @param {boolean} described specifies whether the array is described.
+ * @param {number} type the type of the array elements.
+ * @memberof! proton.Data#
+ */
+_Data_['putARRAYNODE'] = function(described, type) {
+    this._check(_pn_data_put_array(this._data, described, type));
+};
+
+/**
+ * Puts a described node. A described node has two children, the descriptor and
+ * value. These are specified by entering the node and putting the desired values.
+ * <pre>
+ *  var data = new proton.Data();
+ *  data.putDESCRIBEDNODE();
+ *  data.enter();
+ *  data.putSYMBOL('value-descriptor');
+ *  data.putSTRING('the value');
+ *  data.exit();
+ * </pre>
+ * @method putDESCRIBEDNODE
+ * @memberof! proton.Data#
+ */
+_Data_['putDESCRIBEDNODE'] = function() {
+    this._check(_pn_data_put_described(this._data));
+};
 
 /**
  * Puts a null value.
- * @method putNull
+ * @method putNULL
  * @memberof! proton.Data#
  */
-_Data_['putNull'] = function() {
+_Data_['putNULL'] = function() {
     this._check(_pn_data_put_null(this._data));
 };
 
 /**
  * Puts a boolean value.
- * @method putBoolean
+ * @method putBOOL
  * @memberof! proton.Data#
  * @param {boolean} b a boolean value.
  */
-_Data_['putBoolean'] = function(b) {
+_Data_['putBOOL'] = function(b) {
     this._check(_pn_data_put_bool(this._data, b));
 };
 
 /**
  * Puts a unsigned byte value.
- * @method putUnsignedByte
+ * @method putUBYTE
  * @memberof! proton.Data#
  * @param {number} ub an integral value.
  */
-_Data_['putUnsignedByte'] = function(ub) {
+_Data_['putUBYTE'] = function(ub) {
     this._check(_pn_data_put_ubyte(this._data, ub));
 };
 
 /**
  * Puts a signed byte value.
- * @method putByte
+ * @method putBYTE
  * @memberof! proton.Data#
  * @param {number} b an integral value.
  */
-_Data_['putByte'] = function(b) {
+_Data_['putBYTE'] = function(b) {
     this._check(_pn_data_put_byte(this._data, b));
 };
 
 /**
  * Puts a unsigned short value.
- * @method putUnsignedShort
+ * @method putUSHORT
  * @memberof! proton.Data#
  * @param {number} us an integral value.
  */
-_Data_['putUnsignedShort'] = function(us) {
+_Data_['putUSHORT'] = function(us) {
     this._check(_pn_data_put_ushort(this._data, us));
 };
 
 /**
  * Puts a signed short value.
- * @method putShort
+ * @method putSHORT
  * @memberof! proton.Data#
  * @param {number} s an integral value.
  */
-_Data_['putShort'] = function(s) {
+_Data_['putSHORT'] = function(s) {
     this._check(_pn_data_put_short(this._data, s));
 };
 
 /**
  * Puts a unsigned integer value.
- * @method putUnsignedInteger
+ * @method putUINT
  * @memberof! proton.Data#
  * @param {number} ui an integral value.
  */
-_Data_['putUnsignedInteger'] = function(ui) {
+_Data_['putUINT'] = function(ui) {
     this._check(_pn_data_put_uint(this._data, ui));
 };
 
 /**
  * Puts a signed integer value.
- * @method putInteger
+ * @method putINT
  * @memberof! proton.Data#
  * @param {number} i an integral value.
  */
-_Data_['putInteger'] = function(i) {
+_Data_['putINT'] = function(i) {
     this._check(_pn_data_put_int(this._data, i));
 };
 
 /**
  * Puts a signed char value.
- * @method putChar
+ * @method putCHAR
  * @memberof! proton.Data#
- * @param {number} c a single character.
+ * @param {(string|number)} c a single character expressed either as a string or a number.
  */
-_Data_['putChar'] = function(c) {
+_Data_['putCHAR'] = function(c) {
+    c = Data.isString(c) ? c.charCodeAt(0) : c;
     this._check(_pn_data_put_char(this._data, c));
 };
 
 /**
- * Puts a unsigned long value.
- * @method putUnsignedLong
+ * Puts a unsigned long value. N.B. large values can suffer from a loss of
+ * precision as JavaScript numbers are restricted to 64 bit double values.
+ * @method putULONG
  * @memberof! proton.Data#
  * @param {number} ul an integral value.
  */
-_Data_['putUnsignedLong'] = function(ul) {
-    this._check(_pn_data_put_ulong(this._data, ul));
+_Data_['putULONG'] = function(ul) {
+    // If the supplied number exceeds the range of Data.Long invert it before
+    // constructing the Data.Long.
+    ul = (ul >= Data.Long.TWO_PWR_63_DBL_) ? (ul = -(Data.Long.TWO_PWR_64_DBL_ - ul)) : ul;
+    var long = Data.Long.fromNumber(ul);
+    this._check(_pn_data_put_ulong(this._data, long.getLowBitsUnsigned(), long.getHighBits()));
 };
 
 /**
- * Puts a signed long value.
- * @method putLong
+ * Puts a signed long value. N.B. large values can suffer from a loss of
+ * precision as JavaScript numbers are restricted to 64 bit double values.
+ * @method putLONG
  * @memberof! proton.Data#
  * @param {number} i an integral value.
  */
-_Data_['putLong'] = function(l) {
-console.log("putLong " + l);
-
+_Data_['putLONG'] = function(l) {
     var long = Data.Long.fromNumber(l);
     this._check(_pn_data_put_long(this._data, long.getLowBitsUnsigned(), long.getHighBits()));
 };
 
 /**
  * Puts a timestamp.
- * @method putTimestamp
+ * @method putTIMESTAMP
  * @memberof! proton.Data#
- * @param {number} t an integral value.
+ * @param {Date} d a Date value.
  */
-_Data_['putTimestamp'] = function(t) {
-console.log("putTimestamp not properly implemented yet");
-    this._check(_pn_data_put_timestamp(this._data, t));
+_Data_['putTIMESTAMP'] = function(d) {
+    // Note that a timestamp is a 64 bit number so we have to use a proton.Data.Long.
+    var timestamp = Data.Long.fromNumber(d.valueOf());
+    this._check(_pn_data_put_timestamp(this._data, timestamp.getLowBitsUnsigned(), timestamp.getHighBits()));
 };
 
 /**
- * Puts a float value.
- * @method putFloat
+ * Puts a float value. N.B. converting between floats and doubles is imprecise
+ * so the resulting value might not quite be what you expect.
+ * @method putFLOAT
  * @memberof! proton.Data#
  * @param {number} f a floating point value.
  */
-_Data_['putFloat'] = function(f) {
-console.log("putFloat f = " + f);
+_Data_['putFLOAT'] = function(f) {
     this._check(_pn_data_put_float(this._data, f));
 };
 
 /**
  * Puts a double value.
- * @method putDouble
+ * @method putDOUBLE
  * @memberof! proton.Data#
  * @param {number} d a floating point value.
  */
-_Data_['putDouble'] = function(d) {
+_Data_['putDOUBLE'] = function(d) {
     this._check(_pn_data_put_double(this._data, d));
 };
 
 /**
  * Puts a decimal32 value.
- * @method putDecimal32
+ * @method putDECIMAL32
  * @memberof! proton.Data#
  * @param {number} d a decimal32 value.
  */
-_Data_['putDecimal32'] = function(d) {
+_Data_['putDECIMAL32'] = function(d) {
     this._check(_pn_data_put_decimal32(this._data, d));
 };
 
 /**
  * Puts a decimal64 value.
- * @method putDecimal64
+ * @method putDECIMAL64
  * @memberof! proton.Data#
  * @param {number} d a decimal64 value.
  */
-_Data_['putDecimal64'] = function(d) {
+_Data_['putDECIMAL64'] = function(d) {
     this._check(_pn_data_put_decimal64(this._data, d));
 };
 
 /**
  * Puts a decimal128 value.
- * @method putDecimal128
+ * @method putDECIMAL128
  * @memberof! proton.Data#
  * @param {number} d a decimal128 value.
  */
-_Data_['putDecimal128'] = function(d) {
+_Data_['putDECIMAL128'] = function(d) {
     this._check(_pn_data_put_decimal128(this._data, d));
 };
 
@@ -1967,7 +2284,7 @@ _Data_['putDecimal128'] = function(d) {
  * Puts a UUID value.
  * @method putUUID
  * @memberof! proton.Data#
- * @param {proton.Data.UUID} u a uuid value
+ * @param {proton.Data.Uuid} u a uuid value
  */
 _Data_['putUUID'] = function(u) {
     var sp = Runtime.stackSave();
@@ -1976,12 +2293,12 @@ _Data_['putUUID'] = function(u) {
 };
 
 /**
- * Puts a binary value.
- * @method putBinary
+ * Puts a binary value consuming the underlying raw data in the process.
+ * @method putBINARY
  * @memberof! proton.Data#
  * @param {proton.Data.Binary} b a binary value.
  */
-_Data_['putBinary'] = function(b) {
+_Data_['putBINARY'] = function(b) {
     var sp = Runtime.stackSave();
     // The implementation here is a bit "quirky" due to some low-level details
     // of the interaction between emscripten and LLVM and the use of pn_bytes.
@@ -1999,20 +2316,20 @@ _Data_['putBinary'] = function(b) {
     // The compiled pn_data_put_binary takes the pn_bytes_t by reference not value.
     this._check(_pn_data_put_binary(this._data, bytes));
 
-    // After calling _pn_data_put_binary the underlying data object "owns" the
+    // After calling _pn_data_put_binary the underlying Data object "owns" the
     // binary data, so we can call free on the proton.Data.Binary instance to
     // release any storage it has acquired back to the emscripten heap.
-    b.free();
+    b['free']();
     Runtime.stackRestore(sp);
 };
 
 /**
  * Puts a unicode string value.
- * @method putString
+ * @method putSTRING
  * @memberof! proton.Data#
  * @param {string} s a unicode string value.
  */
-_Data_['putString'] = function(s) {
+_Data_['putSTRING'] = function(s) {
     var sp = Runtime.stackSave();
     // The implementation here is a bit "quirky" due to some low-level details
     // of the interaction between emscripten and LLVM and the use of pn_bytes.
@@ -2045,11 +2362,11 @@ _Data_['putString'] = function(s) {
  * open-ended, typically the both number and size of symbols in use for any
  * given application will be small, e.g. small enough that it is reasonable to
  * cache all the distinct values. Symbols are encoded as ASCII characters.
- * @method putSymbol
+ * @method putSYMBOL
  * @memberof! proton.Data#
- * @param {proton.Data.Symbol} s the symbol name.
+ * @param {proton.Data.Symbol|string} s the symbol name.
  */
-_Data_['putSymbol'] = function(s) {
+_Data_['putSYMBOL'] = function(s) {
     var sp = Runtime.stackSave();
     // The implementation here is a bit "quirky" due to some low-level details
     // of the interaction between emscripten and LLVM and the use of pn_bytes.
@@ -2076,116 +2393,220 @@ _Data_['putSymbol'] = function(s) {
     Runtime.stackRestore(sp);
 };
 
-// TODO getArray and isDescribed
+/**
+ * If the current node is a list node, return the number of elements,
+ * otherwise return zero. List elements can be accessed by entering
+ * the list.
+ * <pre>
+ *  var count = data.getLISTNODE();
+ *  data.enter();
+ *  for (var i = 0; i < count; i++) {
+ *      var type = data.next();
+ *      if (type === proton.Data.STRING) {
+ *          console.log(data.getSTRING());
+ *      }
+ *  }
+ *  data.exit();
+ * </pre>
+ * @method getLISTNODE
+ * @memberof! proton.Data#
+ * @returns {number} the number of elements if the current node is a list,
+ *          zero otherwise.
+ */
+_Data_['getLISTNODE'] = function() {
+    return _pn_data_get_list(this._data);
+};
+
+/**
+ * If the current node is a map, return the number of child elements,
+ * otherwise return zero. Key value pairs can be accessed by entering
+ * the map.
+ * <pre>
+ *  var count = data.getMAPNODE();
+ *  data.enter();
+ *  for (var i = 0; i < count/2; i++) {
+ *      var type = data.next();
+ *      if (type === proton.Data.STRING) {
+ *          console.log(data.getSTRING());
+ *      }
+ *  }
+ *  data.exit();
+ * </pre>
+ * @method getMAPNODE
+ * @memberof! proton.Data#
+ * @returns {number} the number of elements if the current node is a list,
+ *          zero otherwise.
+ */
+_Data_['getMAPNODE'] = function() {
+    return _pn_data_get_map(this._data);
+};
+
+/**
+ * If the current node is an array, return an object containing the tuple of the
+ * element count, a boolean indicating whether the array is described, and the
+ * type of each element, otherwise return {count: 0, described: false, type: null).
+ * Array data can be accessed by entering the array.
+ * <pre>
+ *  // Read an array of strings with a symbolic descriptor
+ *  var metadata = data.getARRAYNODE();
+ *  var count = metadata.count;
+ *  data.enter();
+ *  data.next();
+ *  console.log("Descriptor:" + data.getSYMBOL());
+ *  for (var i = 0; i < count; i++) {
+ *      var type = data.next();
+ *      console.log("Element:" + data.getSTRING());
+ *  }
+ *  data.exit();
+ * </pre>
+ * @method getARRAYNODE
+ * @memberof! proton.Data#
+ * @returns {object} the tuple of the element count, a boolean indicating whether
+ *          the array is described, and the type of each element.
+ */
+_Data_['getARRAYNODE'] = function() {
+    var count = _pn_data_get_array(this._data);
+    var described = (_pn_data_is_array_described(this._data) > 0);
+    var type = _pn_data_get_array_type(this._data);
+    type = (type == -1) ? null : type;
+    return {'count': count, 'described': described, 'type': type};
+};
+
+/**
+ * Checks if the current node is a described node. The descriptor and value may
+ * be accessed by entering the described node.
+ * <pre>
+ *  // read a symbolically described string
+ *  assert(data.isDESCRIBEDNODE()); // will error if the current node is not described
+ *  data.enter();
+ *  console.log(data.getSYMBOL());
+ *  console.log(data.getSTRING());
+ *  data.exit();
+ * </pre>
+ * @method isDESCRIBEDNODE
+ * @memberof! proton.Data#
+ * @returns {boolean} true iff the current node is a described, false otherwise.
+ */
+_Data_['isDESCRIBEDNODE'] = function() {
+    return _pn_data_is_described(this._data);
+};
 
 /**
- * @method getNull
+ * @method getNULL
  * @memberof! proton.Data#
- * @return a null value.
+ * @returns a null value.
  */
-_Data_['getNull'] = function() {
+_Data_['getNULL'] = function() {
     return null;
 };
 
 /**
  * Checks if the current node is a null.
- * @method isNull
+ * @method isNULL
  * @memberof! proton.Data#
  * @returns {boolean} true iff the current node is null.
  */
-_Data_['isNull'] = function() {
+_Data_['isNULL'] = function() {
     return (_pn_data_is_null(this._data) > 0);
 };
 
 /**
- * @method getBoolean
+ * @method getBOOL
  * @memberof! proton.Data#
  * @returns {boolean} a boolean value if the current node is a boolean, returns
  *          false otherwise.
  */
-_Data_['getBoolean'] = function() {
+_Data_['getBOOL'] = function() {
     return (_pn_data_get_bool(this._data) > 0);
 };
 
 /**
- * @method getUnsignedByte
+ * @method getUBYTE
  * @memberof! proton.Data#
  * @returns {number} value if the current node is an unsigned byte, returns 0 otherwise.
  */
-_Data_['getUnsignedByte'] = function() {
+_Data_['getUBYTE'] = function() {
     return _pn_data_get_ubyte(this._data) & 0xFF; // & 0xFF converts to unsigned;
 };
 
 /**
- * @method getByte
+ * @method getBYTE
  * @memberof! proton.Data#
  * @returns {number} value if the current node is a signed byte, returns 0 otherwise.
  */
-_Data_['getByte'] = function() {
+_Data_['getBYTE'] = function() {
     return _pn_data_get_byte(this._data);
 };
 
 /**
- * @return value if the current node is an unsigned short, returns 0 otherwise.
+ * @method getUSHORT
+ * @memberof! proton.Data#
+ * @returns {number} value if the current node is an unsigned short, returns 0 otherwise.
  */
-_Data_['getUnsignedShort'] = function() {
+_Data_['getUSHORT'] = function() {
     return _pn_data_get_ushort(this._data) & 0xFFFF; // & 0xFFFF converts to unsigned;
 };
 
 /**
- * @method getShort
+ * @method getSHORT
  * @memberof! proton.Data#
  * @returns {number} value if the current node is a signed short, returns 0 otherwise.
  */
-_Data_['getShort'] = function() {
+_Data_['getSHORT'] = function() {
     return _pn_data_get_short(this._data);
 };
 
 /**
- * @method getUnsignedInteger
+ * @method getUINT
  * @memberof! proton.Data#
  * @returns {number} value if the current node is an unsigned int, returns 0 otherwise.
  */
-_Data_['getUnsignedInteger'] = function() {
+_Data_['getUINT'] = function() {
     var value = _pn_data_get_uint(this._data);
     return (value > 0) ? value : 4294967296 + value; // 4294967296 == 2^32
 };
 
 /**
- * @method getInteger
+ * @method getINT
  * @memberof! proton.Data#
  * @returns {number} value if the current node is a signed int, returns 0 otherwise.
  */
-_Data_['getInteger'] = function() {
-    return _pn_data_put_int(this._data);
+_Data_['getINT'] = function() {
+    return _pn_data_get_int(this._data);
 };
 
 /**
- * @method getChar
+ * @method getCHAR
  * @memberof! proton.Data#
  * @returns {string} the character represented by the unicode value of the current node.
  */
-_Data_['getChar'] = function() {
+_Data_['getCHAR'] = function() {
     return String.fromCharCode(_pn_data_get_char(this._data));
 };
 
 /**
- * @method getUnsignedLong
+ * Retrieve an unsigned long value. N.B. large values can suffer from a loss of
+ * precision as JavaScript numbers are restricted to 64 bit double values.
+ * @method getULONG
  * @memberof! proton.Data#
- * @returns {number} value if the current node is an unsigned long, returns 0 otherwise.
+ * @returns {proton.Data.Long} value if the current node is an unsigned long, returns 0 otherwise.
  */
-_Data_['getUnsignedLong'] = function() {
-console.log("getUnsignedLong");
-    return _pn_data_get_ulong(this._data);
+_Data_['getULONG'] = function() {
+    var low = _pn_data_get_ulong(this._data);
+    var high = Runtime.getTempRet0();
+    var long = new Data.Long(low, high);
+    long = long.toNumber();
+    return (long > 0) ? long : Data.Long.TWO_PWR_64_DBL_ + long;
 };
 
 /**
- * @method getLong
+ * Retrieve a signed long value. N.B. large values can suffer from a loss of
+ * precision as JavaScript numbers are restricted to 64 bit double values.
+ * @method getLONG
  * @memberof! proton.Data#
- * @returns {number} value if the current node is a signed long, returns 0 otherwise.
+ * @returns {proton.Data.Long} value if the current node is a signed long, returns 0 otherwise.
  */
-_Data_['getLong'] = function() {
-console.log("getLong");
+_Data_['getLONG'] = function() {
     // Getting the long is a little tricky as it is a 64 bit number. The way
     // emscripten handles this is to return the low 32 bits directly and pass
     // the high 32 bits via the tempRet0 variable. We use Data.Long to hold
@@ -2195,75 +2616,81 @@ console.log("getLong");
     var high = Runtime.getTempRet0();
     var long = new Data.Long(low, high);
     long = long.toNumber();
-
-console.log("Data.getLong() long = " + long);
-
     return long;
 };
 
 /**
- * @method getTimestamp
+ * @method getTIMESTAMP
  * @memberof! proton.Data#
- * @returns {number} value if the current node is a timestamp, returns 0 otherwise.
+ * @returns {Date} a native JavaScript Date instance representing the timestamp.
  */
-_Data_['getTimestamp'] = function() {
-console.log("getTimestamp not properly implemented yet");
-return 123456;
-    //return _pn_data_get_timestamp(this._data);
+_Data_['getTIMESTAMP'] = function() {
+    // Getting the timestamp is a little tricky as it is a 64 bit number. The way
+    // emscripten handles this is to return the low 32 bits directly and pass
+    // the high 32 bits via the tempRet0 variable. We use Data.Long to hold
+    // the 64 bit number and Data.Long.toNumber() to convert it back into a
+    // JavaScript number.
+    var low =  _pn_data_get_timestamp(this._data);
+    var high = Runtime.getTempRet0();
+    var long = new Data.Long(low, high);
+    long = long.toNumber();
+    return new Date(long);
 };
 
 /**
- * @method getFloat
+ * Retrieves a  float value. N.B. converting between floats and doubles is imprecise
+ * so the resulting value might not quite be what you expect.
+ * @method getFLOAT
  * @memberof! proton.Data#
  * @returns {number} value if the current node is a float, returns 0 otherwise.
  */
-_Data_['getFloat'] = function() {
+_Data_['getFLOAT'] = function() {
     return _pn_data_get_float(this._data);
 };
 
 /**
- * @method getDouble
+ * @method getDOUBLE
  * @memberof! proton.Data#
  * @returns {number} value if the current node is a double, returns 0 otherwise.
  */
-_Data_['getDouble'] = function() {
+_Data_['getDOUBLE'] = function() {
     return _pn_data_get_double(this._data);
 };
 
 /**
- * @method getDecimal32
+ * @method getDECIMAL32
  * @memberof! proton.Data#
  * @returns {number} value if the current node is a decimal32, returns 0 otherwise.
  */
-_Data_['getDecimal32'] = function() {
-console.log("getDecimal32 not properly implemented yet");
+_Data_['getDECIMAL32'] = function() {
+console.log("getDECIMAL32 not properly implemented yet");
     return _pn_data_get_decimal32(this._data);
 };
 
 /**
- * @method getDecimal64
+ * @method getDECIMAL64
  * @memberof! proton.Data#
  * @returns {number} value if the current node is a decimal64, returns 0 otherwise.
  */
-_Data_['getDecimal64'] = function() {
-console.log("getDecimal64 not properly implemented yet");
+_Data_['getDECIMAL64'] = function() {
+console.log("getDECIMAL64 not properly implemented yet");
     return _pn_data_get_decimal64(this._data);
 };
 
 /**
- * @method getDecimal128
+ * @method getDECIMAL128
  * @memberof! proton.Data#
  * @returns {number} value if the current node is a decimal128, returns 0 otherwise.
  */
-_Data_['getDecimal128'] = function() {
-console.log("getDecimal128 not properly implemented yet");
+_Data_['getDECIMAL128'] = function() {
+console.log("getDECIMAL128 not properly implemented yet");
     return _pn_data_get_decimal128(this._data);
 };
 
 /**
  * @method getUUID
  * @memberof! proton.Data#
- * @return {proton.Data.UUID} value if the current node is a UUID, returns null otherwise.
+ * @returns {proton.Data.Uuid} value if the current node is a UUID, returns null otherwise.
  */
 _Data_['getUUID'] = function() {
     var sp = Runtime.stackSave();
@@ -2277,7 +2704,7 @@ _Data_['getUUID'] = function() {
     _pn_data_get_uuid(bytes, this._data);
 
     // Create a new UUID from the bytes
-    var uuid = new Data['UUID'](bytes);
+    var uuid = new Data['Uuid'](bytes);
 
     // Tidy up the memory that we allocated on emscripten's stack.
     Runtime.stackRestore(sp);
@@ -2286,11 +2713,11 @@ _Data_['getUUID'] = function() {
 };
 
 /**
- * @method getBinary
+ * @method getBINARY
  * @memberof! proton.Data#
  * @returns {proton.Data.Binary} value if the current node is a Binary, returns null otherwise.
  */
-_Data_['getBinary'] = function() {
+_Data_['getBINARY'] = function() {
     var sp = Runtime.stackSave();
     // The implementation here is a bit "quirky" due to some low-level details
     // of the interaction between emscripten and LLVM and the use of pn_bytes.
@@ -2322,11 +2749,11 @@ _Data_['getBinary'] = function() {
 
 /**
  * Gets a unicode String value from the current node.
- * @method getString
+ * @method getSTRING
  * @memberof! proton.Data#
- * @return {string} value if the current node is a String, returns "" otherwise.
+ * @returns {string} value if the current node is a String, returns "" otherwise.
  */
-_Data_['getString'] = function() {
+_Data_['getSTRING'] = function() {
     var sp = Runtime.stackSave();
     // The implementation here is a bit "quirky" due to some low-level details
     // of the interaction between emscripten and LLVM and the use of pn_bytes.
@@ -2362,11 +2789,11 @@ _Data_['getString'] = function() {
  * open-ended, typically the both number and size of symbols in use for any
  * given application will be small, e.g. small enough that it is reasonable to
  * cache all the distinct values. Symbols are encoded as ASCII characters.
- * @method getSymbol
+ * @method getSYMBOL
  * @memberof! proton.Data#
- * @return {proton.Data.Symbol} value if the current node is a Symbol, returns "" otherwise.
+ * @returns {proton.Data.Symbol} value if the current node is a Symbol, returns "" otherwise.
  */
-_Data_['getSymbol'] = function() {
+_Data_['getSYMBOL'] = function() {
     var sp = Runtime.stackSave();
     // The implementation here is a bit "quirky" due to some low-level details
     // of the interaction between emscripten and LLVM and the use of pn_bytes.
@@ -2396,18 +2823,65 @@ _Data_['getSymbol'] = function() {
     return new Data['Symbol'](string);
 };
 
+/**
+ * Performs a deep copy of the current {@link proton.Data} instance and returns it
+ * @method copy
+ * @memberof! proton.Data#
+ * @returns {proton.Data} a copy of the current {@link proton.Data} instance.
+ */
+_Data_['copy'] = function() {
+    var copy = new Data();
+    this._check(_pn_data_copy(copy._data, this._data));
+    return copy;
+};
 
-// TODO copy, format and dump
+/**
+ * Format the encoded AMQP Data into a string representation and return it.
+ * @method format
+ * @memberof! proton.Data#
+ * @returns {string} a formatted string representation of the encoded Data.
+ */
+_Data_['format'] = function() {
+    var size = 1024; // Pass by reference variable - need to use setValue to initialise it.
+    while (true) {
+        setValue(size, size, 'i32'); // Set pass by reference variable.
+        var bytes = _malloc(size);   // Allocate storage from emscripten heap.
+        var err = _pn_data_format(this._data, bytes, size);
+        var size = getValue(size, 'i32'); // Dereference the real size value;
+
+        if (err === Module['Error']['OVERFLOW']) {
+            _free(bytes);
+            size *= 2;
+        } else {
+            var string = Pointer_stringify(bytes);
+            _free(bytes);
+            this._check(err)
+            return string;
+        }
+    }
+};
 
+/**
+ * Print the internal state of the {@link proton.Data} in human readable form.
+ * TODO. This seems to "crash" if compound nodes such as DESCRIBED, MAP or LIST
+ * are present in the tree, this is most likely a problem with the underlying C
+ * implementation as all the other navigation and format methods work - need to
+ * check by testing with some native C code.
+ * @method dump
+ * @memberof! proton.Data#
+ */
+_Data_['dump'] = function() {
+    _pn_data_dump(this._data);
+};
 
 /**
  * Serialise a Native JavaScript Object into an AMQP Map.
- * @method putDictionary
+ * @method putMAP
  * @memberof! proton.Data#
  * @param {object} object the Native JavaScript Object that we wish to serialise.
  */
-_Data_['putDictionary'] = function(object) {
-    this['putMap']();
+_Data_['putMAP'] = function(object) {
+    this['putMAPNODE']();
     this['enter']();
     for (var key in object) {
         if (object.hasOwnProperty(key)) {
@@ -2420,18 +2894,18 @@ _Data_['putDictionary'] = function(object) {
 
 /**
  * Deserialise from an AMQP Map into a Native JavaScript Object.
- * @method getDictionary
+ * @method getMAP
  * @memberof! proton.Data#
  * @returns {object} the deserialised Native JavaScript Object.
  */
-_Data_['getDictionary'] = function() {
+_Data_['getMAP'] = function() {
     if (this['enter']()) {
         var result = {};
         while (this['next']()) {
             var key = this['getObject']();
             var value = null;
             if (this['next']()) {
-                value = this['getObject']()
+                value = this['getObject']();
             }
             result[key] = value;
         }
@@ -2442,26 +2916,26 @@ _Data_['getDictionary'] = function() {
 
 /**
  * Serialise a Native JavaScript Array into an AMQP List.
- * @method putJSArray
+ * @method putLIST
  * @memberof! proton.Data#
  * @param {Array} array the Native JavaScript Array that we wish to serialise.
  */
-_Data_['putJSArray'] = function(array) {
-    this['putList']();
+_Data_['putLIST'] = function(array) {
+    this['putLISTNODE']();
     this['enter']();
     for (var i = 0, len = array.length; i < len; i++) {
-        this['putObject'](array[i])
+        this['putObject'](array[i]);
     }
     this['exit']();
 };
 
 /**
  * Deserialise from an AMQP List into a Native JavaScript Array.
- * @method getJSArray
+ * @method getLIST
  * @memberof! proton.Data#
- * @returns {array} the deserialised Native JavaScript Array.
+ * @returns {Array} the deserialised Native JavaScript Array.
  */
-_Data_['getJSArray'] = function() {
+_Data_['getLIST'] = function() {
     if (this['enter']()) {
         var result = [];
         while (this['next']()) {
@@ -2473,6 +2947,150 @@ _Data_['getJSArray'] = function() {
 };
 
 /**
+ * Serialise a proton.Data.Described into an AMQP Described.
+ * @method putDESCRIBED
+ * @memberof! proton.Data#
+ * @param {proton.Data.Described} d the proton.Data.Described that we wish to serialise.
+ */
+_Data_['putDESCRIBED'] = function(d) {
+    this['putDESCRIBEDNODE']();
+    this['enter']();
+    this['putObject'](d['descriptor']);
+    this['putObject'](d['value']);
+    this['exit']();
+};
+
+/**
+ * Deserialise from an AMQP Described into a proton.Data.Described.
+ * @method getDESCRIBED
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Described} the deserialised proton.Data.Described.
+ */
+_Data_['getDESCRIBED'] = function() {
+    if (this['enter']()) {
+        this['next']();
+        var descriptor = this['getObject']();
+        this['next']();
+        var value = this['getObject']();
+        this['exit']();
+        return new Data['Described'](value, descriptor);
+    }
+};
+
+/**
+ * Serialise a proton.Data.Array or JavaScript TypedArray into an AMQP Array.
+ * @method putARRAY
+ * @memberof! proton.Data#
+ * @param {object} a the proton.Data.Array or TypedArray that we wish to serialise.
+ */
+_Data_['putARRAY'] = function(a) {
+    var type = 1;
+    var descriptor = 'TypedArray';
+    var array = a;
+
+    if (a instanceof Data['Array']) { // Array is a proton.Data.Array
+        type = Data[a['type']]; // Find the integer type from its name string.
+        descriptor = a['descriptor'];
+        array = a['elements'];
+    } else { // Array is a Native JavaScript TypedArray so work out the right type.
+        if (a instanceof Int8Array) {
+            type = Data['BYTE'];
+        } else if (a instanceof Uint8Array || a instanceof Uint8ClampedArray) {
+            type = Data['UBYTE'];
+        } else if (a instanceof Int16Array) {
+            type = Data['SHORT'];
+        } else if (a instanceof Uint16Array) {
+            type = Data['USHORT'];
+        } else if (a instanceof Int32Array) {
+            type = Data['INT'];
+        } else if (a instanceof Uint32Array) {
+            type = Data['UINT'];
+        } else if (a instanceof Float32Array) {
+            type = Data['FLOAT'];
+        } else if (a instanceof Float64Array) {
+            type = Data['DOUBLE'];
+        }
+    }
+
+    var described = descriptor != null;
+
+    this['putARRAYNODE'](described, type);
+    this['enter']();
+    if (described) {
+        this['putObject'](descriptor);
+    }
+    var putter = 'put' + Data['TypeNames'][type];
+    for (var i = 0, len = array.length; i < len; i++) {
+        var value = array[i];
+        value = (value instanceof Data.TypedNumber) ? value.value : value;
+        this[putter](value);
+    }
+    this['exit']();
+};
+
+/**
+ * Deserialise from an AMQP Array into a proton.Data.Array.
+ * @method getARRAY
+ * @memberof! proton.Data#
+ * @returns {proton.Data.Array} the deserialised proton.Data.Array.
+ */
+_Data_['getARRAY'] = function() {
+    var metadata = this['getARRAYNODE']();
+    var count = metadata['count'];
+    var described = metadata['described'];
+    var type = metadata['type'];
+
+    if (type === null) {
+        return null;
+    }
+
+    var elements = null;
+    if (typeof ArrayBuffer === 'function') {
+        if (type === Data['BYTE']) {
+            elements = new Int8Array(count);
+        } else if (type === Data['UBYTE']) {
+            elements = new Uint8Array(count);
+        } else if (type === Data['SHORT']) {
+            elements = new Int16Array(count);
+        } else if (type === Data['USHORT']) {
+            elements = new Uint16Array(count);
+        } else if (type === Data['INT']) {
+            elements = new Int32Array(count);
+        } else if (type === Data['UINT']) {
+            elements = new Uint32Array(count);
+        } else if (type === Data['FLOAT']) {
+            elements = new Float32Array(count);
+        } else if (type === Data['DOUBLE']) {
+            elements = new Float64Array(count);
+        } else {
+            elements = new Array(count);
+        }
+    } else {
+        elements = new Array(count);
+    }
+
+    if (this['enter']()) {
+        var descriptor; // Deliberately initialised as undefined not null.
+        if (described) {
+            this['next']();
+            descriptor = this['getObject']();
+        }
+
+        for (var i = 0; i < count; i++) {
+            this['next']();
+            elements[i] = this['getObject']();
+        }
+
+        this['exit']();
+        if (descriptor === 'TypedArray') {
+            return elements;
+        } else {
+            return new Data['Array'](type, elements, descriptor);
+        }
+    }
+};
+
+/**
  * This method is the entry point for serialising native JavaScript types into
  * AMQP types. In an ideal world there would be a nice clean one to one mapping
  * and we could employ a look-up table but in practice the JavaScript type system
@@ -2485,32 +3103,33 @@ _Data_['getJSArray'] = function() {
 _Data_['putObject'] = function(obj) {
 console.log("Data.putObject");
 
-
 console.log("obj = " + obj);
 //console.log("typeof obj = " + (typeof obj));
 //console.log("obj prototype = " + Object.prototype.toString.call(obj));
 
     if (obj == null) { // == Checks for null and undefined.
-console.log("obj is null");
-        this['putNull']();
+        this['putNULL']();
     } else if (Data.isString(obj)) {
-console.log("obj is String");
-
         var quoted = obj.match(/(['"])[^'"]*\1/);
-        if (quoted) {
-            quoted = quoted[0].slice(1, -1);
-console.log("obj is quoted String " + quoted);
-            this['putString'](quoted);
-        } else {
-            // TODO check for stringified numbers.
-            this['putString'](obj);
-        }   
-    } else if (obj instanceof Data['UUID']) {
+        if (quoted) { // If a quoted string extract the string inside the quotes.
+            obj = quoted[0].slice(1, -1);
+        }
+        this['putSTRING'](obj);
+    } else if (obj instanceof Date) {
+        this['putTIMESTAMP'](obj);
+    } else if (obj instanceof Data['Uuid']) {
         this['putUUID'](obj);
     } else if (obj instanceof Data['Binary']) {
-        this['putBinary'](obj);
+        this['putBINARY'](obj);
     } else if (obj instanceof Data['Symbol']) {
-        this['putSymbol'](obj);
+        this['putSYMBOL'](obj);
+    } else if (obj instanceof Data['Described']) {
+        this['putDESCRIBED'](obj);
+    } else if (obj instanceof Data['Array']) {
+        this['putARRAY'](obj);
+    } else if (obj.buffer && (typeof ArrayBuffer === 'function') && 
+               obj.buffer instanceof ArrayBuffer) {
+        this['putARRAY'](obj);
     } else if (obj instanceof Data.TypedNumber) { // Dot notation used for "protected" inner class.
         // Call the appropriate serialisation method based upon the numerical type.
         this['put' + obj.type](obj.value);
@@ -2519,42 +3138,37 @@ console.log("obj is quoted String " + quoted);
          * This block encodes standard JavaScript numbers by making some inferences.
          * Encoding JavaScript numbers is surprisingly complex and has several
          * gotchas. The code here tries to do what the author believes is the
-         * most intuitive encoding of the native JavaScript Number. It first
+         * most "intuitive" encoding of the native JavaScript Number. It first
          * tries to identify if the number is an integer or floating point type
          * by checking if the number modulo 1 is zero (i.e. if it has a remainder
          * then it's a floating point type, which is encoded here as a double).
          * If the number is an integer type a test is made to check if it is a
-         * 32 bit Int value. N.B. JavaScript automagically coerces floating
-         * point numbers with a zero Fractional Part into an exact integer so
+         * 32 bit Int value. N.B. gotcha - JavaScript automagically coerces floating
+         * point numbers with a zero Fractional Part into an *exact* integer so
          * numbers like 1.0, 100.0 etc. will be encoded as int or long here,
          * which is unlikely to be what is wanted. There's no easy "transparent"
          * way around this. The TypedNumber approach above allows applications
-         * to express more explicitly what is require, for example 1.0.asFloat()
-         * (1).asUnsignedByte(), (5).asLong() etc.
+         * to express more explicitly what is required, for example (1.0).float()
+         * (1).ubyte(), (5).long() etc.
          */
         if (obj % 1 === 0) {
-console.log(obj + " is Integer Type " + (obj|0));
             if (obj === (obj|0)) { // the |0 coerces to a 32 bit value.
-                // 32 bit integer - encode as an Integer.
-console.log(obj + " is Int ");
-                this['putInteger'](obj);
+                // 32 bit integer - encode as an INT.
+                this['putINT'](obj);
             } else { // Longer than 32 bit - encode as a Long.
-console.log(obj + " is Long");
-                this['putLong'](obj);
+                this['putLONG'](obj);
             }
         } else { // Floating point type - encode as a Double
-console.log(obj + " is Float Type");
-            this['putDouble'](obj);
+            this['putDOUBLE'](obj);
         }
     } else if (Data.isBoolean(obj)) {
-        this['putBoolean'](obj);
+        this['putBOOL'](obj);
     } else if (Data.isArray(obj)) { // Native JavaScript Array
-        this['putJSArray'](obj);
+        this['putLIST'](obj);
     } else {
-        this['putDictionary'](obj);
+        this['putMAP'](obj);
     }
 };
-_Data_.putObject = _Data_['putObject'];
 
 /**
  * @method getObject
@@ -2562,18 +3176,10 @@ _Data_.putObject = _Data_['putObject'];
  * @returns {object} the JavaScript Object or primitive being deserialised.
  */
 _Data_['getObject'] = function() {
-console.log("Data.getObject: not fully implemented yet");
-
-    var type = this.type();
-console.log("type = " + type);
-
-    var getter = Data.GetMappings[type];
-
-console.log("getter = " + getter);
-
+    var type = Data['TypeNames'][this.type()];
+    type = type ? type : 'NULL';
+    var getter = 'get' + type;
     return this[getter]();
 };
-_Data_.getObject = _Data_['getObject'];
-
 
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6aed8542/proton-c/bindings/javascript/data-test.js
----------------------------------------------------------------------
diff --git a/proton-c/bindings/javascript/data-test.js b/proton-c/bindings/javascript/data-test.js
deleted file mode 100644
index 6904bc9..0000000
--- a/proton-c/bindings/javascript/data-test.js
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-/**
- * Unit tests for the Data Class.
- * TODO this is just some random stuff at the moment - need to port the python codec test.
- */
-
-// Check if the environment is Node.js and if so import the required library.
-if (typeof exports !== "undefined" && exports !== null) {
-    proton = require("../../../bld/proton-c/bindings/javascript/proton.js");
-}
-
-
-try {
-
-    var messenger = new proton.Messenger();
-
-    console.log("name = " + messenger.getName());
-
-    console.log("timeout = " + messenger.getTimeout());
-
-    console.log("isBlocking = " + messenger.isBlocking());
-
-    messenger.setIncomingWindow(1234);
-    console.log("incoming window = " + messenger.getIncomingWindow());
-
-    messenger.setOutgoingWindow(5678);
-    console.log("outgoing window = " + messenger.getOutgoingWindow());
-
-
-    messenger.start();
-    console.log("isStopped = " + messenger.isStopped());
-
-
-    //messenger.subscribe("amqp://narnia");
-    var subscription = messenger.subscribe("amqp://~0.0.0.0");
-    console.log("subscription address = " + subscription.getAddress());
-
-
-    var message = new proton.Message();
-    message.setAddress("amqp://localhost:5672");
-    console.log("message address = " + message.getAddress());
-
-    message.setSubject("UK.WEATHER");
-    console.log("message subject = " + message.getSubject());
-
-
-    messenger.stop();
-    console.log("isStopped = " + messenger.isStopped());
-
-
-
-    message.free();
-
-    messenger.free();
-
-} catch(e) {
-    console.log("Caught Exception " + e);
-}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


Mime
View raw message