zoukankan      html  css  js  c++  java
  • 一个纯JavaScript AMF 协议接口应用

    json2.js

    /*
        http://www.JSON.org/json2.js
        2010-03-20

        Public Domain.

        NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.

        See http://www.JSON.org/js.html


        This code should be minified before deployment.
        See http://javascript.crockford.com/jsmin.html

        USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
        NOT CONTROL.


        This file creates a global JSON object containing two methods: stringify
        and parse.

            JSON.stringify(value, replacer, space)
                value       any JavaScript value, usually an object or array.

                replacer    an optional parameter that determines how object
                            values are stringified for objects. It can be a
                            function or an array of strings.

                space       an optional parameter that specifies the indentation
                            of nested structures. If it is omitted, the text will
                            be packed without extra whitespace. If it is a number,
                            it will specify the number of spaces to indent at each
                            level. If it is a string (such as '\t' or ' '),
                            it contains the characters used to indent at each level.

                This method produces a JSON text from a JavaScript value.

                When an object value is found, if the object contains a toJSON
                method, its toJSON method will be called and the result will be
                stringified. A toJSON method does not serialize: it returns the
                value represented by the name/value pair that should be serialized,
                or undefined if nothing should be serialized. The toJSON method
                will be passed the key associated with the value, and this will be
                bound to the value

                For example, this would serialize Dates as ISO strings.

                    Date.prototype.toJSON = function (key) {
                        function f(n) {
                            // Format integers to have at least two digits.
                            return n < 10 ? '0' + n : n;
                        }

                        return this.getUTCFullYear()   + '-' +
                             f(this.getUTCMonth() + 1) + '-' +
                             f(this.getUTCDate())      + 'T' +
                             f(this.getUTCHours())     + ':' +
                             f(this.getUTCMinutes())   + ':' +
                             f(this.getUTCSeconds())   + 'Z';
                    };

                You can provide an optional replacer method. It will be passed the
                key and value of each member, with this bound to the containing
                object. The value that is returned from your method will be
                serialized. If your method returns undefined, then the member will
                be excluded from the serialization.

                If the replacer parameter is an array of strings, then it will be
                used to select the members to be serialized. It filters the results
                such that only members with keys listed in the replacer array are
                stringified.

                Values that do not have JSON representations, such as undefined or
                functions, will not be serialized. Such values in objects will be
                dropped; in arrays they will be replaced with null. You can use
                a replacer function to replace those with JSON values.
                JSON.stringify(undefined) returns undefined.

                The optional space parameter produces a stringification of the
                value that is filled with line breaks and indentation to make it
                easier to read.

                If the space parameter is a non-empty string, then that string will
                be used for indentation. If the space parameter is a number, then
                the indentation will be that many spaces.

                Example:

                text = JSON.stringify(['e', {pluribus: 'unum'}]);
                // text is '["e",{"pluribus":"unum"}]'


                text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
                // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'

                text = JSON.stringify([new Date()], function (key, value) {
                    return this[key] instanceof Date ?
                        'Date(' + this[key] + ')' : value;
                });
                // text is '["Date(---current time---)"]'


            JSON.parse(text, reviver)
                This method parses a JSON text to produce an object or array.
                It can throw a SyntaxError exception.

                The optional reviver parameter is a function that can filter and
                transform the results. It receives each of the keys and values,
                and its return value is used instead of the original value.
                If it returns what it received, then the structure is not modified.
                If it returns undefined then the member is deleted.

                Example:

                // Parse the text. Values that look like ISO date strings will
                // be converted to Date objects.

                myData = JSON.parse(text, function (key, value) {
                    var a;
                    if (typeof value === 'string') {
                        a =
    /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
                        if (a) {
                            return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
                                +a[5], +a[6]));
                        }
                    }
                    return value;
                });

                myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
                    var d;
                    if (typeof value === 'string' &&
                            value.slice(0, 5) === 'Date(' &&
                            value.slice(-1) === ')') {
                        d = new Date(value.slice(5, -1));
                        if (d) {
                            return d;
                        }
                    }
                    return value;
                });


        This is a reference implementation. You are free to copy, modify, or
        redistribute.
    */

    /*jslint evil: true, strict: false */

    /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
        call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
        getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
        lastIndex, length, parse, prototype, push, replace, slice, stringify,
        test, toJSON, toString, valueOf
    */


    // Create a JSON object only if one does not already exist. We create the
    // methods in a closure to avoid creating global variables.

    if (!this.JSON) {
        this.JSON = {};
    }

    (function () {

        function f(n) {
            // Format integers to have at least two digits.
            return n < 10 ? '0' + n : n;
        }

        if (typeof Date.prototype.toJSON !== 'function') {

            Date.prototype.toJSON = function (key) {

                return isFinite(this.valueOf()) ?
                       this.getUTCFullYear()   + '-' +
                     f(this.getUTCMonth() + 1) + '-' +
                     f(this.getUTCDate())      + 'T' +
                     f(this.getUTCHours())     + ':' +
                     f(this.getUTCMinutes())   + ':' +
                     f(this.getUTCSeconds())   + 'Z' : null;
            };

            String.prototype.toJSON =
            Number.prototype.toJSON =
            Boolean.prototype.toJSON = function (key) {
                return this.valueOf();
            };
        }

        var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
            escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
            gap,
            indent,
            meta = {    // table of character substitutions
                '\b': '\\b',
                '\t': '\\t',
                '\n': '\\n',
                '\f': '\\f',
                '\r': '\\r',
                '"' : '\\"',
                '\\': '\\\\'
            },
            rep;


        function quote(string) {

    // If the string contains no control characters, no quote characters, and no
    // backslash characters, then we can safely slap some quotes around it.
    // Otherwise we must also replace the offending characters with safe escape
    // sequences.

            escapable.lastIndex = 0;
            return escapable.test(string) ?
                '"' + string.replace(escapable, function (a) {
                    var c = meta[a];
                    return typeof c === 'string' ? c :
                        '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
                }) + '"' :
                '"' + string + '"';
        }


        function str(key, holder) {

    // Produce a string from holder[key].

            var i,          // The loop counter.
                k,          // The member key.
                v,          // The member value.
                length,
                mind = gap,
                partial,
                value = holder[key];

    // If the value has a toJSON method, call it to obtain a replacement value.

            if (value && typeof value === 'object' &&
                    typeof value.toJSON === 'function') {
                value = value.toJSON(key);
            }

    // If we were called with a replacer function, then call the replacer to
    // obtain a replacement value.

            if (typeof rep === 'function') {
                value = rep.call(holder, key, value);
            }

    // What happens next depends on the value's type.

            switch (typeof value) {
            case 'string':
                return quote(value);

            case 'number':

    // JSON numbers must be finite. Encode non-finite numbers as null.

                return isFinite(value) ? String(value) : 'null';

            case 'boolean':
            case 'null':

    // If the value is a boolean or null, convert it to a string. Note:
    // typeof null does not produce 'null'. The case is included here in
    // the remote chance that this gets fixed someday.

                return String(value);

    // If the type is 'object', we might be dealing with an object or an array or
    // null.

            case 'object':

    // Due to a specification blunder in ECMAScript, typeof null is 'object',
    // so watch out for that case.

                if (!value) {
                    return 'null';
                }

    // Make an array to hold the partial results of stringifying this object value.

                gap += indent;
                partial = [];

    // Is the value an array?

                if (Object.prototype.toString.apply(value) === '[object Array]') {

    // The value is an array. Stringify every element. Use null as a placeholder
    // for non-JSON values.

                    length = value.length;
                    for (i = 0; i < length; i += 1) {
                        partial[i] = str(i, value) || 'null';
                    }

    // Join all of the elements together, separated with commas, and wrap them in
    // brackets.

                    v = partial.length === 0 ? '[]' :
                        gap ? '[\n' + gap +
                                partial.join(',\n' + gap) + '\n' +
                                    mind + ']' :
                              '[' + partial.join(',') + ']';
                    gap = mind;
                    return v;
                }

    // If the replacer is an array, use it to select the members to be stringified.

                if (rep && typeof rep === 'object') {
                    length = rep.length;
                    for (i = 0; i < length; i += 1) {
                        k = rep[i];
                        if (typeof k === 'string') {
                            v = str(k, value);
                            if (v) {
                                partial.push(quote(k) + (gap ? ': ' : ':') + v);
                            }
                        }
                    }
                } else {

    // Otherwise, iterate through all of the keys in the object.

                    for (k in value) {
                        if (Object.hasOwnProperty.call(value, k)) {
                            v = str(k, value);
                            if (v) {
                                partial.push(quote(k) + (gap ? ': ' : ':') + v);
                            }
                        }
                    }
                }

    // Join all of the member texts together, separated with commas,
    // and wrap them in braces.

                v = partial.length === 0 ? '{}' :
                    gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
                            mind + '}' : '{' + partial.join(',') + '}';
                gap = mind;
                return v;
            }
        }

    // If the JSON object does not yet have a stringify method, give it one.

        if (typeof JSON.stringify !== 'function') {
            JSON.stringify = function (value, replacer, space) {

    // The stringify method takes a value and an optional replacer, and an optional
    // space parameter, and returns a JSON text. The replacer can be a function
    // that can replace values, or an array of strings that will select the keys.
    // A default replacer method can be provided. Use of the space parameter can
    // produce text that is more easily readable.

                var i;
                gap = '';
                indent = '';

    // If the space parameter is a number, make an indent string containing that
    // many spaces.

                if (typeof space === 'number') {
                    for (i = 0; i < space; i += 1) {
                        indent += ' ';
                    }

    // If the space parameter is a string, it will be used as the indent string.

                } else if (typeof space === 'string') {
                    indent = space;
                }

    // If there is a replacer, it must be a function or an array.
    // Otherwise, throw an error.

                rep = replacer;
                if (replacer && typeof replacer !== 'function' &&
                        (typeof replacer !== 'object' ||
                         typeof replacer.length !== 'number')) {
                    throw new Error('JSON.stringify');
                }

    // Make a fake root object containing our value under the key of ''.
    // Return the result of stringifying the value.

                return str('', {'': value});
            };
        }


    // If the JSON object does not yet have a parse method, give it one.

        if (typeof JSON.parse !== 'function') {
            JSON.parse = function (text, reviver) {

    // The parse method takes a text and an optional reviver function, and returns
    // a JavaScript value if the text is a valid JSON text.

                var j;

                function walk(holder, key) {

    // The walk method is used to recursively walk the resulting structure so
    // that modifications can be made.

                    var k, v, value = holder[key];
                    if (value && typeof value === 'object') {
                        for (k in value) {
                            if (Object.hasOwnProperty.call(value, k)) {
                                v = walk(value, k);
                                if (v !== undefined) {
                                    value[k] = v;
                                } else {
                                    delete value[k];
                                }
                            }
                        }
                    }
                    return reviver.call(holder, key, value);
                }


    // Parsing happens in four stages. In the first stage, we replace certain
    // Unicode characters with escape sequences. JavaScript handles many characters
    // incorrectly, either silently deleting them, or treating them as line endings.

                text = String(text);
                cx.lastIndex = 0;
                if (cx.test(text)) {
                    text = text.replace(cx, function (a) {
                        return '\\u' +
                            ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
                    });
                }

    // In the second stage, we run the text against regular expressions that look
    // for non-JSON patterns. We are especially concerned with '()' and 'new'
    // because they can cause invocation, and '=' because it can cause mutation.
    // But just to be safe, we want to reject all unexpected forms.

    // We split the second stage into 4 regexp operations in order to work around
    // crippling inefficiencies in IE's and Safari's regexp engines. First we
    // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
    // replace all simple value tokens with ']' characters. Third, we delete all
    // open brackets that follow a colon or comma or that begin the text. Finally,
    // we look to see that the remaining characters are only whitespace or ']' or
    // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.

                if (/^[\],:{}\s]*$/.
    test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
    replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
    replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {

    // In the third stage we use the eval function to compile the text into a
    // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
    // in JavaScript: it can begin a block or an object literal. We wrap the text
    // in parens to eliminate the ambiguity.

                    j = eval('(' + text + ')');

    // In the optional fourth stage, we recursively walk the new structure, passing
    // each name/value pair to a reviver function for possible transformation.

                    return typeof reviver === 'function' ?
                        walk({'': j}, '') : j;
                }

    // If the text is not JSON parseable, then a SyntaxError is thrown.

                throw new SyntaxError('JSON.parse');
            };
        }
    }());

    //----------------------------------------------

    amf.js

    /*
    amf.js - An AMF library in JavaScript

    Copyright (c) 2010, James Ward - http://www.jamesward.com/
    All rights reserved.

    Redistribution and use in source and binary forms, with or without modification, are
    permitted provided that the following conditions are met:

       1. Redistributions of source code must retain the above copyright notice, this list of
          conditions and the following disclaimer.

       2. Redistributions in binary form must reproduce the above copyright notice, this list
          of conditions and the following disclaimer in the documentation and/or other materials
          provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY JAMES WARD ''AS IS'' AND ANY EXPRESS OR IMPLIED
    WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JAMES WARD OR
    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
    ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
    ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

    The views and conclusions contained in the software and documentation are those of the
    authors and should not be interpreted as representing official policies, either expressed
    or implied, of James Ward.
    */
    function decodeAMF(data)
    {
      var bytes = new a3d.ByteArray(data, a3d.Endian.BIG);

      var version = bytes.readUnsignedShort();
      bytes.objectEncoding = a3d.ObjectEncoding.AMF0;

      var response = new a3d.AMFPacket();

      var remainingBytes;

      // Headers
      var headerCount = bytes.readUnsignedShort();
      for (var h = 0; h < headerCount; h++)
      {
        var headerName = bytes.readUTF();
        var mustUnderstand = bytes.readBoolean();
        bytes.readInt(); // Consume header length...

        // Handle AVM+ type marker
        if (version == a3d.ObjectEncoding.AMF3)
        {
          var typeMarker = bytes.readByte();
          if (typeMarker == a3d.Amf0Types.kAvmPlusObjectType)
            bytes.objectEncoding = a3d.ObjectEncoding.AMF3;
          else
            bytes.pos = bytes.pos - 1;
        }

        var headerValue = bytes.readObject();

       /*
         // Read off the remaining bytes to account for the reset of
         // the by-reference index on each header value
         remainingBytes = new a3d.ByteArray();
         remainingBytes.objectEncoding = bytes.objectEncoding;
         bytes.readBytes(remainingBytes, 0, bytes.length - bytes.pos);
         bytes = remainingBytes;
         remainingBytes = null;
         */
       
        var header = new a3d.AMFHeader(headerName, mustUnderstand, headerValue);
        response.headers.push(header);

        // Reset to AMF0 for next header
        bytes.objectEncoding = a3d.ObjectEncoding.AMF0;
      }

      // Message Bodies
      var messageCount = bytes.readUnsignedShort();
      for (var m = 0; m < messageCount; m++)
      {
        var targetURI = bytes.readUTF();
        var responseURI = bytes.readUTF();
        bytes.readInt(); // Consume message body length...

        // Handle AVM+ type marker
        if (version == a3d.ObjectEncoding.AMF3)
        {
          var typeMarker = bytes.readByte();
          if (typeMarker == a3d.Amf0Types.kAvmPlusObjectType)
            bytes.objectEncoding = a3d.ObjectEncoding.AMF3;
          else
            bytes.pos = bytes.pos - 1;
        }

        var messageBody = bytes.readObject();

        var message = new a3d.AMFMessage(targetURI, responseURI, messageBody);
        response.messages.push(message);

        bytes.objectEncoding = a3d.ObjectEncoding.AMF0;
      }

      return response;
    }

    function dumpHex(bytes)
    {
      var s = "";
      var i = 0;
      var chunk = [];

      while (i < bytes.length)
      {

        if (((i % 16) == 0) && (i != 0))
        {
          s += writeChunk(chunk, 16) + "\n";
          chunk = [];
        }

        chunk.push(bytes.readUnsignedByte());

        i++;
      }
      s += writeChunk(chunk, 16);

      bytes.pos = 0;

      return s;
    }

    function writeChunk(chunk, width)
    {
      var s = "";

      for (var i = 0; i < chunk.length; i++)
      {
        if (((i % 4) == 0) && (i != 0))
        {
          s += " ";
        }

        var b = chunk[i];

        var ss = b.toString(16) + " ";
        if (ss.length == 2)
        {
          ss = "0" + ss;
        }

        s += ss;
      }

      for (var i = 0; i < (width - chunk.length); i++)
      {
        s += "   ";
      }

      var j = Math.floor((width - chunk.length) / 4);
      for (var i = 0; i < j; i++)
      {
        s += " ";
      }

      s += "   ";

      for (var i = 0; i < chunk.length; i++)
      {
        var b = chunk[i];

        if ((b <= 126) && (b > 32))
        {
          var ss = String.fromCharCode(b);
          s += ss;
        }
        else
        {
          s += ".";
        }
      }

      return s;
    }

    /**
     * @preserve
     * Adamia 3D Engine v0.1
     * Copyright (c) 2010 Adam R. Smith
     * Licensed under the new BSD License:
     * http://www.opensource.org/licenses/bsd-license.php
     *
     * Project home: http://code.google.com/p/adamia-3d/
     *
     * Date: 01/12/2010
     */

    if (typeof(a3d) == 'undefined')
    {
      /** @namespace */
      a3d = {};
    }

    // Taken from http://ejohn.org/blog/simple-javascript-inheritance/

    // Inspired by base2 and Prototype
    (function()
    {
      var initializing = false, fnTest = /xyz/.test(function()
      {
        xyz;
      }) ? /\b_super\b/ : /.*/;

      // The base Class implementation (does nothing)
      /** @class */
      this.Class = function()
      {
      };

      // Create a new Class that inherits from this class
      Class.extend = function(prop)
      {
        var _super = this.prototype;

        // Instantiate a base class (but only create the instance,
        // don't run the init constructor)
        initializing = true;
        var prototype = new this();
        initializing = false;

        // Copy the properties over onto the new prototype
        for (var name in prop)
        {
          // Check if we're overwriting an existing function
          prototype[name] = typeof prop[name] == "function" &&
                  typeof _super[name] == "function" && fnTest.test(prop[name]) ?
                  (function(name, fn)
                  {
                    return function()
                    {
                      var tmp = this._super;

                      // Add a new ._super() method that is the same method
                      // but on the super-class
                      this._super = _super[name];

                      // The method only need to be bound temporarily, so we
                      // remove it when we're done executing
                      var ret = fn.apply(this, arguments);
                      this._super = tmp;

                      return ret;
                    };
                  })(name, prop[name]) :
                  prop[name];
        }

        // The dummy class constructor
        function Class()
        {
          // All construction is actually done in the init method
          if (!initializing && this.init)
            this.init.apply(this, arguments);
        }

        // Populate our constructed prototype object
        Class.prototype = prototype;

        // Enforce the constructor to be what we expect
        Class.constructor = Class;

        // And make this class extendable
        Class.extend = arguments.callee;

        return Class;
      };
    })();
    /**
     * Enum for big or little endian.
     * @enum {number}
     */
    a3d.Endian = {
      BIG: 0
      , LITTLE: 1
    };

    a3d.ObjectEncoding = {
      AMF0: 0
      , AMF3: 3
    };

    a3d.Amf0Types = {
      kNumberType:           0
      , kBooleanType:        1
      , kStringType:         2
      , kObjectType:         3
      , kMovieClipType:      4
      , kNullType:           5
      , kUndefinedType:      6
      , kReferenceType:      7
      , kECMAArrayType:      8
      , kObjectEndType:      9
      , kStrictArrayType:   10
      , kDateType:          11
      , kLongStringType:    12
      , kUnsupportedType:   13
      , kRecordsetType:     14
      , kXMLObjectType:     15
      , kTypedObjectType:   16
      , kAvmPlusObjectType: 17
    };

    a3d.Amf3Types = {
      kUndefinedType:    0
      , kNullType:       1
      , kFalseType:      2
      , kTrueType:       3
      , kIntegerType:    4
      , kDoubleType:     5
      , kStringType:     6
      , kXMLType:        7
      , kDateType:       8
      , kArrayType:      9
      , kObjectType:     10
      , kAvmPlusXmlType: 11
      , kByteArrayType:  12
    };


    a3d.AMFMessage = Class.extend({
      targetURL: ""
      , responseURI: ""
      , body: {}

      , init: function(targetURL, responseURI, body)
      {
        this.targetURL = targetURL;
        this.responseURI = responseURI;
        this.body = body;
      }
    });

    a3d.AMFPacket = Class.extend({
      version:  0
      , headers: []
      , messages: []

      , init: function(version)
      {
        this.version = (version !== undefined) ? version : 0;
        this.headers = new Array();
        this.messages = new Array();
      }
    });

    a3d.AMFHeader = Class.extend({
      name: ""
      , mustUnderstand: false
      , data: {}

      , init: function(name, mustUnderstand, data)
      {
        this.name = name;
        this.mustUnderstand = (mustUnderstand != undefined) ? mustUnderstand : false;
        this.data = data;
      }
    });

    /**
     * Attempt to imitate AS3's ByteArray as very high-performance javascript.
     * I aliased the functions to have shorter names, like ReadUInt32 as well as ReadUnsignedInt.
     * I used some code from http://fhtr.blogspot.com/2009/12/3d-models-and-parsing-binary-data-with.html
     * to kick-start it, but I added optimizations and support both big and little endian.
     * Note that you cannot change the endianness after construction.
     * @extends Class
     */
    a3d.ByteArray = Class.extend({
      data: ''
      , length: 0
      , pos: 0
      , pow: Math.pow
      , endian: a3d.Endian.BIG
      , TWOeN23: Math.pow(2, -23)
      , TWOeN52: Math.pow(2, -52)
      , objectEncoding: a3d.ObjectEncoding.AMF0
      , stringTable: []
      , objectTable: []
      , traitTable: []

      /** @constructor */
      , init: function(data, endian)
      {
        this.data = (data !== undefined) ? data : '';
        if (endian !== undefined) this.endian = endian;
        this.length = data.length;

        this.stringTable = new Array();
        this.objectTable = new Array();
        this.traitTable = new Array();

        // Cache the function pointers based on endianness.
        // This avoids doing an if-statement in every function call.
        var funcExt = (endian == a3d.Endian.BIG) ? 'BE' : 'LE';
        var funcs = ['readInt32', 'readInt16', 'readUInt30','readUInt32', 'readUInt16', 'readFloat32', 'readFloat64'];
        for (var func in funcs)
        {
          this[funcs[func]] = this[funcs[func] + funcExt];
        }

        // Add redundant members that match actionscript for compatibility
        var funcMap = {readUnsignedByte: 'readByte', readUnsignedInt: 'readUInt32',
          readFloat: 'readFloat32', readDouble: 'readFloat64', readShort: 'readInt16', readUnsignedShort: 'readUInt16',
          readBoolean: 'readBool', readInt: 'readInt32'};
        for (var func in funcMap)
        {
          this[func] = this[funcMap[func]];
        }
      }

      , readByte: function()
      {
        var cc = this.data.charCodeAt(this.pos++);
        return (cc & 0xFF);
      }

      , writeByte: function(byte)
      {
        this.data += byte;
      }

      , readBool: function()
      {
        return (this.data.charCodeAt(this.pos++) & 0xFF) ? true : false;
      }

      , readUInt30BE: function()
      {
        var ch1 = readByte();
        var ch2 = readByte();
        var ch3 = readByte();
        var ch4 = readByte();

        if (ch1 >= 64)
          return undefined;

        return ch4 | (ch3 << 8) | (ch2 << 16) | (ch1 << 24);
      }

      , readUInt32BE: function()
      {
        var data = this.data, pos = (this.pos += 4) - 4;
        return  ((data.charCodeAt(pos) & 0xFF) << 24) |
                ((data.charCodeAt(++pos) & 0xFF) << 16) |
                ((data.charCodeAt(++pos) & 0xFF) << 8) |
                (data.charCodeAt(++pos) & 0xFF);
      }
      , readInt32BE: function()
      {
        var data = this.data, pos = (this.pos += 4) - 4;
        var x = ((data.charCodeAt(pos) & 0xFF) << 24) |
                ((data.charCodeAt(++pos) & 0xFF) << 16) |
                ((data.charCodeAt(++pos) & 0xFF) << 8) |
                (data.charCodeAt(++pos) & 0xFF);
        return (x >= 2147483648) ? x - 4294967296 : x;
      }

      , readUInt16BE: function()
      {
        var data = this.data, pos = (this.pos += 2) - 2;
        return  ((data.charCodeAt(pos) & 0xFF) << 8) |
                (data.charCodeAt(++pos) & 0xFF);
      }
      , readInt16BE: function()
      {
        var data = this.data, pos = (this.pos += 2) - 2;
        var x = ((data.charCodeAt(pos) & 0xFF) << 8) |
                (data.charCodeAt(++pos) & 0xFF);
        return (x >= 32768) ? x - 65536 : x;
      }

      , readFloat32BE: function()
      {
        var data = this.data, pos = (this.pos += 4) - 4;
        var b1 = data.charCodeAt(pos) & 0xFF,
                b2 = data.charCodeAt(++pos) & 0xFF,
                b3 = data.charCodeAt(++pos) & 0xFF,
                b4 = data.charCodeAt(++pos) & 0xFF;
        var sign = 1 - ((b1 >> 7) << 1);                   // sign = bit 0
        var exp = (((b1 << 1) & 0xFF) | (b2 >> 7)) - 127;  // exponent = bits 1..8
        var sig = ((b2 & 0x7F) << 16) | (b3 << 8) | b4;    // significand = bits 9..31
        if (sig == 0 && exp == -127)
          return 0.0;
        return sign * (1 + this.TWOeN23 * sig) * this.pow(2, exp);
      }

      , readFloat64BE: function()
      {
        var b1 = this.readByte();
        var b2 = this.readByte();
        var b3 = this.readByte();
        var b4 = this.readByte();
        var b5 = this.readByte();
        var b6 = this.readByte();
        var b7 = this.readByte();
        var b8 = this.readByte();

        var sign = 1 - ((b1 >> 7) << 1);         // sign = bit 0
        var exp = (((b1 << 4) & 0x7FF) | (b2 >> 4)) - 1023;     // exponent = bits 1..11

        // This crazy toString() stuff works around the fact that js ints are
        // only 32 bits and signed, giving us 31 bits to work with
        var sig = (((b2 & 0xF) << 16) | (b3 << 8) | b4).toString(2) +
                ((b5 >> 7) ? '1' : '0') +
                (((b5 & 0x7F) << 24) | (b6 << 16) | (b7 << 8) | b8).toString(2); // significand = bits 12..63

        sig = parseInt(sig, 2);

        if (sig == 0 && exp == -1023)
       return 0.0;

      return sign*(1.0 + this.TWOeN52*sig)*this.pow(2, exp);
        /*
        var sig = (((b2 & 0xF) << 16) | (b3 << 8) | b4).toString(2) +
                  (((b5 & 0xF) << 16) | (b6 << 8) | b7).toString(2) +
                  (b8).toString(2);

        // should have 52 bits here
        console.log(sig.length);

        // this doesn't work   sig = parseInt(sig, 2);
       
        var newSig = 0;
        for (var i = 0; i < sig.length; i++)
        {
          var binaryPlace = this.pow(2, sig.length - i - 1);
          var binaryValue = parseInt(sig.charAt(i));
          newSig += binaryPlace * binaryValue;
        }


        if (newSig == 0 && exp == -1023)
          return 0.0;

        var mantissa = this.TWOeN52 * newSig;

        return sign * (1.0 + mantissa) * this.pow(2, exp);
        */
      }

      , readUInt29: function()
      {
        var value;

        // Each byte must be treated as unsigned
        var b = this.readByte() & 0xFF;

        if (b < 128)
          return b;

        value = (b & 0x7F) << 7;
        b = this.readByte() & 0xFF;

        if (b < 128)
          return (value | b);

        value = (value | (b & 0x7F)) << 7;
        b = this.readByte() & 0xFF;

        if (b < 128)
          return (value | b);

        value = (value | (b & 0x7F)) << 8;
        b = this.readByte() & 0xFF;

        return (value | b);
      }

      , readUInt30LE: function()
      {
        var ch1 = readByte();
        var ch2 = readByte();
        var ch3 = readByte();
        var ch4 = readByte();

        if (ch4 >= 64)
          return undefined;

        return ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24);
      }

      , readUInt32LE: function()
      {
        var data = this.data, pos = (this.pos += 4);
        return  ((data.charCodeAt(--pos) & 0xFF) << 24) |
                ((data.charCodeAt(--pos) & 0xFF) << 16) |
                ((data.charCodeAt(--pos) & 0xFF) << 8) |
                (data.charCodeAt(--pos) & 0xFF);
      }
      , readInt32LE: function()
      {
        var data = this.data, pos = (this.pos += 4);
        var x = ((data.charCodeAt(--pos) & 0xFF) << 24) |
                ((data.charCodeAt(--pos) & 0xFF) << 16) |
                ((data.charCodeAt(--pos) & 0xFF) << 8) |
                (data.charCodeAt(--pos) & 0xFF);
        return (x >= 2147483648) ? x - 4294967296 : x;
      }

      , readUInt16LE: function()
      {
        var data = this.data, pos = (this.pos += 2);
        return  ((data.charCodeAt(--pos) & 0xFF) << 8) |
                (data.charCodeAt(--pos) & 0xFF);
      }
      , readInt16LE: function()
      {
        var data = this.data, pos = (this.pos += 2);
        var x = ((data.charCodeAt(--pos) & 0xFF) << 8) |
                (data.charCodeAt(--pos) & 0xFF);
        return (x >= 32768) ? x - 65536 : x;
      }

      , readFloat32LE: function()
      {
        var data = this.data, pos = (this.pos += 4);
        var b1 = data.charCodeAt(--pos) & 0xFF,
                b2 = data.charCodeAt(--pos) & 0xFF,
                b3 = data.charCodeAt(--pos) & 0xFF,
                b4 = data.charCodeAt(--pos) & 0xFF;
        var sign = 1 - ((b1 >> 7) << 1);                   // sign = bit 0
        var exp = (((b1 << 1) & 0xFF) | (b2 >> 7)) - 127;  // exponent = bits 1..8
        var sig = ((b2 & 0x7F) << 16) | (b3 << 8) | b4;    // significand = bits 9..31
        if (sig == 0 && exp == -127)
          return 0.0;
        return sign * (1 + this.TWOeN23 * sig) * this.pow(2, exp);
      }

      , readFloat64LE: function()
      {
        var data = this.data, pos = (this.pos += 8);
        var b1 = data.charCodeAt(--pos) & 0xFF,
                b2 = data.charCodeAt(--pos) & 0xFF,
                b3 = data.charCodeAt(--pos) & 0xFF,
                b4 = data.charCodeAt(--pos) & 0xFF,
                b5 = data.charCodeAt(--pos) & 0xFF,
                b6 = data.charCodeAt(--pos) & 0xFF,
                b7 = data.charCodeAt(--pos) & 0xFF,
                b8 = data.charCodeAt(--pos) & 0xFF;
        var sign = 1 - ((b1 >> 7) << 1);         // sign = bit 0
        var exp = (((b1 << 4) & 0x7FF) | (b2 >> 4)) - 1023;     // exponent = bits 1..11

        // This crazy toString() stuff works around the fact that js ints are
        // only 32 bits and signed, giving us 31 bits to work with
        var sig = (((b2 & 0xF) << 16) | (b3 << 8) | b4).toString(2) +
                ((b5 >> 7) ? '1' : '0') +
                (((b5 & 0x7F) << 24) | (b6 << 16) | (b7 << 8) | b8).toString(2); // significand = bits 12..63

        sig = parseInt(sig, 2);
        if (sig == 0 && exp == -1023)
          return 0.0;
        return sign * (1.0 + this.TWOeN52 * sig) * this.pow(2, exp);
      }

      , readDate: function()
      {
        var time_ms = this.readDouble();
        var tz_min = this.readUInt16();
        return new Date(time_ms + tz_min * 60 * 1000);
      }

      , readString: function(len)
      {
        var str = "";

        while (len > 0)
        {
          str += String.fromCharCode(this.readUnsignedByte());
          len--;
        }
        return str;
      }

      , readUTF: function()
      {
        return this.readString(this.readUnsignedShort());
      }

      , readLongUTF: function()
      {
        return this.readString(this.readUInt30());
      }

      , stringToXML: function(str)
      {
        var xmlDoc;

        if (window.DOMParser)
        {
          var parser = new DOMParser();
          xmlDoc = parser.parseFromString(str, "text/xml");
        }
        else // IE
        {
          xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
          xmlDoc.async = false;
          xmlDoc.loadXML(stc);
        }

        return xmlDoc;
      }

      , readXML: function()
      {
        var xml = this.readLongUTF();

        return this.stringToXML(xml);
      }

      , readStringAMF3: function()
      {
        var ref = this.readUInt29();

        if ((ref & 1) == 0) // This is a reference
          return this.stringTable[(ref >> 1)];

        var len = (ref >> 1);

        if (0 == len)
          return "";

        var str = this.readString(len);

        this.stringTable.push(str);

        return str;
      }

      , readTraits: function(ref)
      {
        var traitInfo = new Object();
        traitInfo.properties = new Array();

        if ((ref & 3) == 1)
          return this.traitTable[(ref >> 2)];

        traitInfo.externalizable = ((ref & 4) == 4);

        traitInfo.dynamic = ((ref & 8) == 8);

        traitInfo.count = (ref >> 4);
        traitInfo.className = this.readStringAMF3();

        this.traitTable.push(traitInfo);

        for (var i = 0; i < traitInfo.count; i++)
        {
          var propName = this.readStringAMF3();
          traitInfo.properties.push(propName);
        }

        return traitInfo;
      }

      , readExternalizable: function(className)
      {
        return this.readObject();
      }

      , readObject: function()
      {
        if (this.objectEncoding == a3d.ObjectEncoding.AMF0)
        {
          return this.readAMF0Object();
        }
        else if (this.objectEncoding == a3d.ObjectEncoding.AMF3)
        {
          return this.readAMF3Object();
        }
      }

      , readAMF0Object: function()
      {
        var marker = this.readByte();

        if (marker == a3d.Amf0Types.kNumberType)
        {
          return this.readDouble();
        }
        else if (marker == a3d.Amf0Types.kBooleanType)
        {
          return this.readBoolean();
        }
        else if (marker == a3d.Amf0Types.kStringType)
        {
          return this.readUTF();
        }
        else if ((marker == a3d.Amf0Types.kObjectType) || (marker == a3d.Amf0Types.kECMAArrayType))
        {
          var o = new Object();

          var ismixed = (marker == 0x08);

          var size = null;
          if (ismixed)
            this.readUInt30();

          while (true)
          {
            var c1 = this.readByte();
            var c2 = this.readByte();
            var name = this.readString((c1 << 8) | c2);
            var k = this.readByte();
            if (k == 0x09)
              break;

            this.pos--;

            o[name] = readObject();
          }

          return o;
        }
        else if (marker == a3d.Amf0Types.kStrictArrayType)
        {
          var size = this.readInt();

          var a = new Array();

          for (var i = 0; i < size; ++i)
          {
            a.push(this.readObject());
          }

          return a;
        }
        else if (marker == a3d.Amf0Types.kTypedObjectType)
        {
          var o = new Object();

          var typeName = this.readUTF();
         
          var propertyName = this.readUTF();
          var type = this.readByte();
          while (type != kObjectEndType)
          {
            var value = this.readObject();
            o[propertyName] = value;

            propertyName = this.readUTF();
            type = this.readByte();
          }

          return o;
        }
        else if (marker == a3d.Amf0Types.kAvmPlusObjectType)
        {
          return this.readAMF3Object();
        }
        else if (marker == a3d.Amf0Types.kNullType)
        {
          return null;
        }
        else if (marker == a3d.Amf0Types.kUndefinedType)
        {
          return undefined;
        }
        else if (marker == a3d.Amf0Types.kReferenceType)
        {
          var refNum = this.readUnsignedShort();

          var value = this.objectTable[refNum];

          return value;
        }
        else if (marker == a3d.Amf0Types.kDateType)
        {
          return this.readDate();
        }
        else if (marker == a3d.Amf0Types.kLongStringType)
        {
          return this.readLongUTF();
        }
        else if (marker == a3d.Amf0Types.kXMLObjectType)
        {
          return this.readXML();
        }
      }

      , readAMF3Object: function()
      {
        var marker = this.readByte();

        if (marker == a3d.Amf3Types.kUndefinedType)
        {
          return undefined;
        }
        else if (marker == a3d.Amf3Types.kNullType)
        {
          return null;
        }
        else if (marker == a3d.Amf3Types.kFalseType)
        {
          return false;
        }
        else if (marker == a3d.Amf3Types.kTrueType)
        {
          return true;
        }
        else if (marker == a3d.Amf3Types.kIntegerType)
        {
          var i = this.readUInt29();

          return i;
        }
        else if (marker == a3d.Amf3Types.kDoubleType)
        {
          return this.readDouble();
        }
        else if (marker == a3d.Amf3Types.kStringType)
        {
          return this.readStringAMF3();
        }
        else if (marker == a3d.Amf3Types.kXMLType)
        {
          return this.readXML();
        }
        else if (marker == a3d.Amf3Types.kDateType)
        {
          var ref = this.readUInt29();

          if ((ref & 1) == 0)
            return this.objectTable[(ref >> 1)];

          var d = this.readDouble();
          var value = new Date(d);
          this.objectTable.push(value);

          return value;
        }
        else if (marker == a3d.Amf3Types.kArrayType)
        {
          var ref = this.readUInt29();

          if ((ref & 1) == 0)
            return this.objectTable[(ref >> 1)];

          var len = (ref >> 1);

          var key = this.readStringAMF3();

          if (key == "")
          {
            var a = new Array();

            for (var i = 0; i < len; i++)
            {
              var value = this.readObject();

              a.push(value);
            }

            return a;
          }

          // mixed array
          var result = {};

          while (key != "")
          {
            result[key] = this.readObject();
            key = this.readStringAMF3();
          }

          for (var i = 0; i < len; i++)
          {
            result[i] = this.readObject();
          }

          return result;
        }
        else if (marker == a3d.Amf3Types.kObjectType)
        {
          var o = new Object();

          var ref = this.readUInt29();

          if ((ref & 1) == 0)
            return this.objectTable[(ref >> 1)];

          var ti = this.readTraits(ref);
          var className = ti.className;
          var externalizable = ti.externalizable;

          if (externalizable)
          {
            o = this.readExternalizable(className);
          }
          else
          {
            var len = ti.properties.length;

            for (var i = 0; i < len; i++)
            {
              var propName = ti.properties[i];

              var value = this.readObject();

              o[propName] = value;
            }

            if (ti.dynamic)
            {
              for (; ;)
              {
                var name = this.readString();
                if (name == null || name.length == 0) break;

                var value = this.readObject();
                o[propName] = value;
              }
            }
          }

          this.objectTable.push(o);

          return o;
        }
        else if (marker == a3d.Amf3Types.kAvmPlusXmlType)
        {
          var ref = this.readUInt29();

          if ((ref & 1) == 0)
            return this.stringToXML(this.objectTable[(ref >> 1)]);

          var len = (ref >> 1);

          if (0 == len)
            return null;


          var str = this.readString(len);

          var xml = this.stringToXML(str);

          this.objectTable.push(xml);

          return xml;
        }
        else if (marker == a3d.Amf3Types.kByteArrayType)
        {
          var ref = this.readUInt29();
          if ((ref & 1) == 0)
            return this.objectTable[(ref >> 1)];

          var len = (ref >> 1);

          var ba = new a3d.ByteArray();

          for (var i = 0; i < len; i++)
          {
            ba.writeByte(this.readByte());
          }

          this.objectTable.push(ba);

          return ba;
        }

      }
    });

    //-----------------------------------------

    应用实例

    <html>
    <head>
      <script type="text/javascript" src="json2.js"></script>
      <script type="text/javascript" src="amf.js"></script>
      <script type="text/vbscript">
              Function BinaryToArray(Binary)
                Dim i
                ReDim byteArray(LenB(Binary))
                For i = 1 To LenB(Binary)
                  byteArray(i-1) = AscB(MidB(Binary, i, 1))
                Next
                BinaryToArray = byteArray
              End Function
      </script>
      <script type="text/javascript">
        var url = "/census2-tests/servlet/CensusServiceServlet?command=getAMF3&rows=20&clientId=6F5A9CE7-802D-CC17-CA35-A4A5611BF796&testId=flex_amf3&sendCensusResultURL=http://www.jamesward.com/census2/SendCensusResult&gzip=true";

        var req;

        function getAMF()
        {
          document.getElementById("output").innerHTML = "<h1>Fetching AMF encoded data using JavaScript from:</h1>" + url + "<br/>";

          if (window.ActiveXObject)
          {
            req = new ActiveXObject("Microsoft.XMLHTTP");
          }
          else if (window.XMLHttpRequest)
          {
            req = new XMLHttpRequest();
            //XHR binary charset opt by Marcus Granado 2006 [http://mgran.blogspot.com]
            req.overrideMimeType('text/plain; charset=x-user-defined');
          }

          req.onreadystatechange = processReqChange;
          req.open("GET", url, true);
          req.send(null);
        }

        function processReqChange()
        {
          if (req.readyState == 4)
          {
            if (req.status == 200)
            {
              var res;
              if (req.responseBody != undefined)
              {
                res = "";
                var a = BinaryToArray(req.responseBody).toArray();
                for (var i = 0; i < a.length; i++)
                {
                  res += String.fromCharCode(a[i]);
                }
              }
              else
              {
                res = req.responseText;
              }

              var o = decodeAMF(res).messages[0].body;
             
              var bytes = new a3d.ByteArray(res, a3d.Endian.BIG);

              var tHtml = "<h2>Decoded data in a table:</h2><table width='100%' cellpadding='4' cellspacing='0' border='1'>";
              for (var i = 0; i < o.length; i++)
              {
                tHtml += "<tr>";
                tHtml += "<td>" + o[i].id + "</td>";
                tHtml += "<td>" + o[i].age + "</td>";
                tHtml += "<td>" + o[i].education + "</td>";
                tHtml += "<td>" + o[i].classOfWorker + "</td>";
                tHtml += "<td>" + o[i].maritalStatus + "</td>";
                tHtml += "<td>" + o[i].race + "</td>";
                tHtml += "<td>" + o[i].sex + "</td>";
                tHtml += "</tr>";
              }
              tHtml += "</table>";

              document.getElementById("output").innerHTML += "<br/>" + tHtml;

              document.getElementById("output").innerHTML += "<br/><h2>hexdump of AMF data:</h2><pre>" + dumpHex(bytes) + "</pre>";

              document.getElementById("output").innerHTML += "<br/><h2>JSON Data representation:</h2>" + JSON.stringify(o);
            }
            else
            {
              alert("There was a problem retrieving the data:\n" + req.statusText);
            }
          }
        }
      </script>
    </head>
    <body onload="getAMF()">

      <div id="output">

      </div>

    </body>
    </html>

  • 相关阅读:
    jQuery事件
    jQuery选择器
    jQuery对象和语法
    jQuery简介
    残差的正态性检验——概率图和QQ-plot图
    https://oldpan.me/深度学习博客
    深度学习的内存消耗在哪里?
    图片缩放
    随机梯度下降批尺寸的影响
    利用PIL.ImageOps.invert实现二值图像黑白反转
  • 原文地址:https://www.cnblogs.com/fx2008/p/2408056.html
Copyright © 2011-2022 走看看