3721 lines
		
	
	
		
			No EOL
		
	
	
		
			168 KiB
			
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			3721 lines
		
	
	
		
			No EOL
		
	
	
		
			168 KiB
			
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/*
 | 
						|
 Copyright 2013 Daniel Wirtz <dcode@dcode.io>
 | 
						|
 | 
						|
 Licensed 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.
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * @license ProtoBuf.js (c) 2013 Daniel Wirtz <dcode@dcode.io>
 | 
						|
 * Released under the Apache License, Version 2.0
 | 
						|
 * see: https://github.com/dcodeIO/ProtoBuf.js for details
 | 
						|
 */
 | 
						|
(function(global) {
 | 
						|
    "use strict";
 | 
						|
    
 | 
						|
    function loadProtoBuf(ByteBuffer) {
 | 
						|
 | 
						|
        /**
 | 
						|
         * The ProtoBuf namespace.
 | 
						|
         * @exports ProtoBuf
 | 
						|
         * @namespace
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        var ProtoBuf = {};
 | 
						|
        
 | 
						|
        /**
 | 
						|
         * ProtoBuf.js version.
 | 
						|
         * @type {string}
 | 
						|
         * @const
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.VERSION = "2.0.5";
 | 
						|
 | 
						|
        /**
 | 
						|
         * Wire types.
 | 
						|
         * @type {Object.<string,number>}
 | 
						|
         * @const
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.WIRE_TYPES = {};
 | 
						|
 | 
						|
        /**
 | 
						|
         * Varint wire type.
 | 
						|
         * @type {number}
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.WIRE_TYPES.VARINT = 0;
 | 
						|
 | 
						|
        /**
 | 
						|
         * Fixed 64 bits wire type.
 | 
						|
         * @type {number}
 | 
						|
         * @const
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.WIRE_TYPES.BITS64 = 1;
 | 
						|
 | 
						|
        /**
 | 
						|
         * Length delimited wire type.
 | 
						|
         * @type {number}
 | 
						|
         * @const
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.WIRE_TYPES.LDELIM = 2;
 | 
						|
 | 
						|
        /**
 | 
						|
         * Start group wire type.
 | 
						|
         * @type {number}
 | 
						|
         * @const
 | 
						|
         * @deprecated Not supported.
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.WIRE_TYPES.STARTGROUP = 3;
 | 
						|
 | 
						|
        /**
 | 
						|
         * End group wire type.
 | 
						|
         * @type {number}
 | 
						|
         * @const
 | 
						|
         * @deprecated Not supported.
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.WIRE_TYPES.ENDGROUP = 4;
 | 
						|
 | 
						|
        /**
 | 
						|
         * Fixed 32 bits wire type.
 | 
						|
         * @type {number}
 | 
						|
         * @const
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.WIRE_TYPES.BITS32 = 5;
 | 
						|
 | 
						|
        /**
 | 
						|
         * Types.
 | 
						|
         * @dict
 | 
						|
         * @type {Object.<string,{name: string, wireType: number}>}
 | 
						|
         * @const
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.TYPES = {
 | 
						|
            // According to the protobuf spec.
 | 
						|
            "int32": {
 | 
						|
                name: "int32",
 | 
						|
                wireType: ProtoBuf.WIRE_TYPES.VARINT
 | 
						|
            },
 | 
						|
            "uint32": {
 | 
						|
                name: "uint32",
 | 
						|
                wireType: ProtoBuf.WIRE_TYPES.VARINT
 | 
						|
            },
 | 
						|
            "sint32": {
 | 
						|
                name: "sint32",
 | 
						|
                wireType: ProtoBuf.WIRE_TYPES.VARINT
 | 
						|
            },
 | 
						|
            "int64": {
 | 
						|
                name: "int64",
 | 
						|
                wireType: ProtoBuf.WIRE_TYPES.VARINT
 | 
						|
            },
 | 
						|
            "uint64": {
 | 
						|
                name: "uint64",
 | 
						|
                wireType: ProtoBuf.WIRE_TYPES.VARINT
 | 
						|
            },
 | 
						|
            "sint64": {
 | 
						|
                name: "sint64",
 | 
						|
                wireType: ProtoBuf.WIRE_TYPES.VARINT
 | 
						|
            },
 | 
						|
            "bool": {
 | 
						|
                name: "bool",
 | 
						|
                wireType: ProtoBuf.WIRE_TYPES.VARINT
 | 
						|
            },
 | 
						|
            "double": {
 | 
						|
                name: "double",
 | 
						|
                wireType: ProtoBuf.WIRE_TYPES.BITS64
 | 
						|
            },
 | 
						|
            "string": {
 | 
						|
                name: "string",
 | 
						|
                wireType: ProtoBuf.WIRE_TYPES.LDELIM
 | 
						|
            },
 | 
						|
            "bytes": {
 | 
						|
                name: "bytes",
 | 
						|
                wireType: ProtoBuf.WIRE_TYPES.LDELIM
 | 
						|
            },
 | 
						|
            "fixed32": {
 | 
						|
                name: "fixed32",
 | 
						|
                wireType: ProtoBuf.WIRE_TYPES.BITS32
 | 
						|
            },
 | 
						|
            "sfixed32": {
 | 
						|
                name: "sfixed32",
 | 
						|
                wireType: ProtoBuf.WIRE_TYPES.BITS32
 | 
						|
            },
 | 
						|
            "fixed64": {
 | 
						|
                name: "fixed64",
 | 
						|
                wireType: ProtoBuf.WIRE_TYPES.BITS64
 | 
						|
            },
 | 
						|
            "sfixed64": {
 | 
						|
                name: "sfixed64",
 | 
						|
                wireType: ProtoBuf.WIRE_TYPES.BITS64
 | 
						|
            },
 | 
						|
            "float": {
 | 
						|
                name: "float",
 | 
						|
                wireType: ProtoBuf.WIRE_TYPES.BITS32
 | 
						|
            },
 | 
						|
            "enum": {
 | 
						|
                name: "enum",
 | 
						|
                wireType: ProtoBuf.WIRE_TYPES.VARINT
 | 
						|
            },
 | 
						|
            "message": {
 | 
						|
                name: "message",
 | 
						|
                wireType: ProtoBuf.WIRE_TYPES.LDELIM
 | 
						|
            }
 | 
						|
        };
 | 
						|
 | 
						|
        /**
 | 
						|
         * @type {?Long}
 | 
						|
         */
 | 
						|
        ProtoBuf.Long = ByteBuffer.Long;
 | 
						|
 | 
						|
        /**
 | 
						|
         * If set to `true`, field names will be converted from underscore notation to camel case. Defaults to `false`.
 | 
						|
         *  Must be set prior to parsing.
 | 
						|
         * @type {boolean}
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.convertFieldsToCamelCase = false;
 | 
						|
        
 | 
						|
        /**
 | 
						|
         * @alias ProtoBuf.Util
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.Util = (function() {
 | 
						|
            "use strict";
 | 
						|
        
 | 
						|
            // Object.create polyfill
 | 
						|
            // ref: https://developer.mozilla.org/de/docs/JavaScript/Reference/Global_Objects/Object/create
 | 
						|
            if (!Object.create) {
 | 
						|
                /** @expose */
 | 
						|
                Object.create = function (o) {
 | 
						|
                    if (arguments.length > 1) {
 | 
						|
                        throw new Error('Object.create implementation only accepts the first parameter.');
 | 
						|
                    }
 | 
						|
                    function F() {}
 | 
						|
                    F.prototype = o;
 | 
						|
                    return new F();
 | 
						|
                };
 | 
						|
            }
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * ProtoBuf utilities.
 | 
						|
             * @exports ProtoBuf.Util
 | 
						|
             * @namespace
 | 
						|
             */
 | 
						|
            var Util = {};
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Flag if running in node or not.
 | 
						|
             * @type {boolean}
 | 
						|
             * @const
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Util.IS_NODE = (typeof window === 'undefined' || !window.window) && typeof require === 'function' && typeof process !== 'undefined' && typeof process["nextTick"] === 'function';
 | 
						|
            
 | 
						|
            /**
 | 
						|
             * Constructs a XMLHttpRequest object.
 | 
						|
             * @return {XMLHttpRequest}
 | 
						|
             * @throws {Error} If XMLHttpRequest is not supported
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Util.XHR = function() {
 | 
						|
                // No dependencies please, ref: http://www.quirksmode.org/js/xmlhttp.html
 | 
						|
                var XMLHttpFactories = [
 | 
						|
                    function () {return new XMLHttpRequest()},
 | 
						|
                    function () {return new ActiveXObject("Msxml2.XMLHTTP")},
 | 
						|
                    function () {return new ActiveXObject("Msxml3.XMLHTTP")},
 | 
						|
                    function () {return new ActiveXObject("Microsoft.XMLHTTP")}
 | 
						|
                ];
 | 
						|
                /** @type {?XMLHttpRequest} */
 | 
						|
                var xhr = null;
 | 
						|
                for (var i=0;i<XMLHttpFactories.length;i++) {
 | 
						|
                    try { xhr = XMLHttpFactories[i](); }
 | 
						|
                    catch (e) { continue; }
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
                if (!xhr) throw(new Error("XMLHttpRequest is not supported"));
 | 
						|
                return xhr;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Fetches a resource.
 | 
						|
             * @param {string} path Resource path
 | 
						|
             * @param {function(?string)=} callback Callback receiving the resource's contents. If omitted the resource will
 | 
						|
             *   be fetched synchronously. If the request failed, contents will be null.
 | 
						|
             * @return {?string|undefined} Resource contents if callback is omitted (null if the request failed), else undefined.
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Util.fetch = function(path, callback) {
 | 
						|
                if (callback && typeof callback != 'function') callback = null;
 | 
						|
                if (Util.IS_NODE) {
 | 
						|
                    if (callback) {
 | 
						|
                        require("fs").readFile(path, function(err, data) {
 | 
						|
                            if (err) {
 | 
						|
                                callback(null);
 | 
						|
                            }
 | 
						|
                            else callback(""+data);
 | 
						|
                        });
 | 
						|
                    } else {
 | 
						|
                        try {
 | 
						|
                            return require("fs").readFileSync(path);
 | 
						|
                        } catch (e) {
 | 
						|
                            return null;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                } else {
 | 
						|
                    var xhr = Util.XHR();
 | 
						|
                    xhr.open('GET', path, callback ? true : false);
 | 
						|
                    // xhr.setRequestHeader('User-Agent', 'XMLHTTP/1.0');
 | 
						|
                    xhr.setRequestHeader('Accept', 'text/plain');
 | 
						|
                    if (typeof xhr.overrideMimeType === 'function') xhr.overrideMimeType('text/plain');
 | 
						|
                    if (callback) {
 | 
						|
                        xhr.onreadystatechange = function() {
 | 
						|
                            if (xhr.readyState != 4) return;
 | 
						|
                            if (/* remote */ xhr.status == 200 || /* local */ (xhr.status == 0 && typeof xhr.responseText === 'string')) {
 | 
						|
                                callback(xhr.responseText);
 | 
						|
                            } else {
 | 
						|
                                callback(null);
 | 
						|
                            }
 | 
						|
                        };
 | 
						|
                        if (xhr.readyState == 4) return;
 | 
						|
                        xhr.send(null);
 | 
						|
                    } else {
 | 
						|
                        xhr.send(null);
 | 
						|
                        if (/* remote */ xhr.status == 200 || /* local */ (xhr.status == 0 && typeof xhr.responseText === 'string')) {
 | 
						|
                            return xhr.responseText;
 | 
						|
                        }
 | 
						|
                        return null;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Tests if an object is an array.
 | 
						|
             * @param {*} obj Object to test
 | 
						|
             * @returns {boolean} true if it is an array, else false
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Util.isArray = function(obj) {
 | 
						|
                if (!obj) return false;
 | 
						|
                if (obj instanceof Array) return true;
 | 
						|
                if (Array.isArray) return Array.isArray(obj);
 | 
						|
                return Object.prototype.toString.call(obj) === "[object Array]";
 | 
						|
            };
 | 
						|
            
 | 
						|
            return Util;
 | 
						|
        })();        
 | 
						|
        /**
 | 
						|
         * @alias ProtoBuf.Lang
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.Lang = (function() {
 | 
						|
            "use strict";
 | 
						|
            
 | 
						|
            /**
 | 
						|
             * ProtoBuf Language.
 | 
						|
             * @exports ProtoBuf.Lang
 | 
						|
             * @type {Object.<string,string|RegExp>}
 | 
						|
             * @namespace
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            var Lang = { // Look, so cute!
 | 
						|
                OPEN: "{",
 | 
						|
                CLOSE: "}",
 | 
						|
                OPTOPEN: "[",
 | 
						|
                OPTCLOSE: "]",
 | 
						|
                OPTEND: ",",
 | 
						|
                EQUAL: "=",
 | 
						|
                END: ";",
 | 
						|
                STRINGOPEN: '"',
 | 
						|
                STRINGCLOSE: '"',
 | 
						|
                COPTOPEN: '(',
 | 
						|
                COPTCLOSE: ')',
 | 
						|
        
 | 
						|
                DELIM: /[\s\{\}=;\[\],"\(\)]/g,
 | 
						|
                
 | 
						|
                KEYWORD: /^(?:package|option|import|message|enum|extend|service|syntax|extensions)$/,
 | 
						|
                RULE: /^(?:required|optional|repeated)$/,
 | 
						|
                TYPE: /^(?:double|float|int32|uint32|sint32|int64|uint64|sint64|fixed32|sfixed32|fixed64|sfixed64|bool|string|bytes)$/,
 | 
						|
                NAME: /^[a-zA-Z][a-zA-Z_0-9]*$/,
 | 
						|
                OPTNAME: /^(?:[a-zA-Z][a-zA-Z_0-9]*|\([a-zA-Z][a-zA-Z_0-9]*\))$/,
 | 
						|
                TYPEDEF: /^[a-zA-Z][a-zA-Z_0-9]*$/,
 | 
						|
                TYPEREF: /^(?:\.?[a-zA-Z][a-zA-Z_0-9]*)+$/,
 | 
						|
                FQTYPEREF: /^(?:\.[a-zA-Z][a-zA-Z_0-9]*)+$/,
 | 
						|
                NUMBER: /^-?(?:[1-9][0-9]*|0|0x[0-9a-fA-F]+|0[0-7]+|[0-9]*\.[0-9]+)$/,
 | 
						|
                NUMBER_DEC: /^(?:[1-9][0-9]*|0)$/,
 | 
						|
                NUMBER_HEX: /^0x[0-9a-fA-F]+$/,
 | 
						|
                NUMBER_OCT: /^0[0-7]+$/,
 | 
						|
                NUMBER_FLT: /^[0-9]*\.[0-9]+$/,
 | 
						|
                ID: /^(?:[1-9][0-9]*|0|0x[0-9a-fA-F]+|0[0-7]+)$/,
 | 
						|
                NEGID: /^\-?(?:[1-9][0-9]*|0|0x[0-9a-fA-F]+|0[0-7]+)$/,
 | 
						|
                WHITESPACE: /\s/,
 | 
						|
                STRING: /"([^"\\]*(\\.[^"\\]*)*)"/g,
 | 
						|
                BOOL: /^(?:true|false)$/i,
 | 
						|
        
 | 
						|
                ID_MIN: 1,
 | 
						|
                ID_MAX: 0x1FFFFFFF
 | 
						|
            };
 | 
						|
            return Lang;
 | 
						|
        })();
 | 
						|
                
 | 
						|
        /**
 | 
						|
         * Utilities to parse .proto files.
 | 
						|
         * @namespace
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.DotProto = {}; // Not present in "noparse" builds
 | 
						|
        
 | 
						|
        /**
 | 
						|
         * @alias ProtoBuf.DotProto.Tokenizer
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.DotProto.Tokenizer = (function(Lang) {
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Constructs a new Tokenizer.
 | 
						|
             * @exports ProtoBuf.DotProto.Tokenizer
 | 
						|
             * @class A ProtoBuf .proto Tokenizer.
 | 
						|
             * @param {string} proto Proto to tokenize
 | 
						|
             * @constructor
 | 
						|
             */
 | 
						|
            var Tokenizer = function(proto) {
 | 
						|
                
 | 
						|
                /**
 | 
						|
                 * Source to parse.
 | 
						|
                 * @type {string}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.source = ""+proto;
 | 
						|
                
 | 
						|
                /**
 | 
						|
                 * Current index.
 | 
						|
                 * @type {number}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.index = 0;
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Current line.
 | 
						|
                 * @type {number}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.line = 1;
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Stacked values.
 | 
						|
                 * @type {Array}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.stack = [];
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Whether currently reading a string or not.
 | 
						|
                 * @type {boolean}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.readingString = false;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Reads a string beginning at the current index.
 | 
						|
             * @return {string} The string
 | 
						|
             * @throws {Error} If it's not a valid string
 | 
						|
             * @private
 | 
						|
             */
 | 
						|
            Tokenizer.prototype._readString = function() {
 | 
						|
                Lang.STRING.lastIndex = this.index-1; // Include the open quote
 | 
						|
                var match;
 | 
						|
                if ((match = Lang.STRING.exec(this.source)) !== null) {
 | 
						|
                    var s = match[1];
 | 
						|
                    this.index = Lang.STRING.lastIndex;
 | 
						|
                    this.stack.push(Lang.STRINGCLOSE);
 | 
						|
                    return s;
 | 
						|
                }
 | 
						|
                throw(new Error("Illegal string value at line "+this.line+", index "+this.index));
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Gets the next token and advances by one.
 | 
						|
             * @return {?string} Token or `null` on EOF
 | 
						|
             * @throws {Error} If it's not a valid proto file
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Tokenizer.prototype.next = function() {
 | 
						|
                if (this.stack.length > 0) {
 | 
						|
                    return this.stack.shift();
 | 
						|
                }
 | 
						|
                if (this.index >= this.source.length) {
 | 
						|
                    return null; // No more tokens
 | 
						|
                }
 | 
						|
                if (this.readingString) {
 | 
						|
                    this.readingString = false;
 | 
						|
                    return this._readString();
 | 
						|
                }
 | 
						|
                var repeat, last;
 | 
						|
                do {
 | 
						|
                    repeat = false;
 | 
						|
                    // Strip white spaces
 | 
						|
                    while (Lang.WHITESPACE.test(last = this.source.charAt(this.index))) {
 | 
						|
                        this.index++;
 | 
						|
                        if (last === "\n") this.line++;
 | 
						|
                        if (this.index === this.source.length) return null;
 | 
						|
                    }
 | 
						|
                    // Strip comments
 | 
						|
                    if (this.source.charAt(this.index) === '/') {
 | 
						|
                        if (this.source.charAt(++this.index) === '/') { // Single line
 | 
						|
                            while (this.source.charAt(this.index) !== "\n") {
 | 
						|
                                this.index++;
 | 
						|
                                if (this.index == this.source.length) return null;
 | 
						|
                            }
 | 
						|
                            this.index++;
 | 
						|
                            this.line++;
 | 
						|
                            repeat = true;
 | 
						|
                        } else if (this.source.charAt(this.index) === '*') { /* Block */
 | 
						|
                            last = '';
 | 
						|
                            while (last+(last=this.source.charAt(this.index)) !== '*/') {
 | 
						|
                                this.index++;
 | 
						|
                                if (last === "\n") this.line++;
 | 
						|
                                if (this.index === this.source.length) return null;
 | 
						|
                            }
 | 
						|
                            this.index++;
 | 
						|
                            repeat = true;
 | 
						|
                        } else {
 | 
						|
                            throw(new Error("Invalid comment at line "+this.line+": /"+this.source.charAt(this.index)+" ('/' or '*' expected)"));
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                } while (repeat);
 | 
						|
                if (this.index === this.source.length) return null;
 | 
						|
        
 | 
						|
                // Read the next token
 | 
						|
                var end = this.index;
 | 
						|
                Lang.DELIM.lastIndex = 0;
 | 
						|
                var delim = Lang.DELIM.test(this.source.charAt(end));
 | 
						|
                if (!delim) {
 | 
						|
                    end++;
 | 
						|
                    while(end < this.source.length && !Lang.DELIM.test(this.source.charAt(end))) {
 | 
						|
                        end++;
 | 
						|
                    }
 | 
						|
                } else {
 | 
						|
                    end++;
 | 
						|
                }
 | 
						|
                var token = this.source.substring(this.index, this.index = end);
 | 
						|
                if (token === Lang.STRINGOPEN) {
 | 
						|
                    this.readingString = true;
 | 
						|
                }
 | 
						|
                return token;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Peeks for the next token.
 | 
						|
             * @return {?string} Token or `null` on EOF
 | 
						|
             * @throws {Error} If it's not a valid proto file
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Tokenizer.prototype.peek = function() {
 | 
						|
                if (this.stack.length == 0) {
 | 
						|
                    var token = this.next();
 | 
						|
                    if (token === null) return null;
 | 
						|
                    this.stack.push(token);
 | 
						|
                }
 | 
						|
                return this.stack[0];
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Returns a string representation of this object.
 | 
						|
             * @return {string} String representation as of "Tokenizer(index/length)"
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Tokenizer.prototype.toString = function() {
 | 
						|
                return "Tokenizer("+this.index+"/"+this.source.length+" at line "+this.line+")";
 | 
						|
            };
 | 
						|
            
 | 
						|
            return Tokenizer;
 | 
						|
            
 | 
						|
        })(ProtoBuf.Lang);
 | 
						|
                
 | 
						|
        /**
 | 
						|
         * @alias ProtoBuf.DotProto.Parser
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.DotProto.Parser = (function(ProtoBuf, Lang, Tokenizer) {
 | 
						|
            "use strict";
 | 
						|
            
 | 
						|
            /**
 | 
						|
             * Constructs a new Parser.
 | 
						|
             * @exports ProtoBuf.DotProto.Parser
 | 
						|
             * @class A ProtoBuf .proto parser.
 | 
						|
             * @param {string} proto Protocol source
 | 
						|
             * @constructor
 | 
						|
             */
 | 
						|
            var Parser = function(proto) {
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Tokenizer.
 | 
						|
                 * @type {ProtoBuf.DotProto.Tokenizer}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.tn = new Tokenizer(proto);
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Runs the parser.
 | 
						|
             * @return {{package: string|null, messages: Array.<object>, enums: Array.<object>, imports: Array.<string>, options: object<string,*>}}
 | 
						|
             * @throws {Error} If the source cannot be parsed
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Parser.prototype.parse = function() {
 | 
						|
                var topLevel = {
 | 
						|
                    "name": "[ROOT]", // temporary
 | 
						|
                    "package": null,
 | 
						|
                    "messages": [],
 | 
						|
                    "enums": [],
 | 
						|
                    "imports": [],
 | 
						|
                    "options": {},
 | 
						|
                    "services": []
 | 
						|
                };
 | 
						|
                var token, header = true;
 | 
						|
                do {
 | 
						|
                    token = this.tn.next();
 | 
						|
                    if (token == null) {
 | 
						|
                        break; // No more messages
 | 
						|
                    }
 | 
						|
                    if (token == 'package') {
 | 
						|
                        if (!header) {
 | 
						|
                            throw(new Error("Illegal package definition at line "+this.tn.line+": Must be declared before the first message or enum"));
 | 
						|
                        }
 | 
						|
                        if (topLevel["package"] !== null) {
 | 
						|
                            throw(new Error("Illegal package definition at line "+this.tn.line+": Package already declared"));
 | 
						|
                        }
 | 
						|
                        topLevel["package"] = this._parsePackage(token);
 | 
						|
                    } else if (token == 'import') {
 | 
						|
                        if (!header) {
 | 
						|
                            throw(new Error("Illegal import definition at line "+this.tn.line+": Must be declared before the first message or enum"));
 | 
						|
                        }
 | 
						|
                        topLevel.imports.push(this._parseImport(token));
 | 
						|
                    } else if (token === 'message') {
 | 
						|
                        this._parseMessage(topLevel, token);
 | 
						|
                        header = false;
 | 
						|
                    } else if (token === 'enum') {
 | 
						|
                        this._parseEnum(topLevel, token);
 | 
						|
                        header = false;
 | 
						|
                    } else if (token === 'option') {
 | 
						|
                        if (!header) {
 | 
						|
                            throw(new Error("Illegal option definition at line "+this.tn.line+": Must be declared before the first message or enum"));
 | 
						|
                        }
 | 
						|
                        this._parseOption(topLevel, token);
 | 
						|
                    } else if (token === 'service') {
 | 
						|
                        this._parseService(topLevel, token);
 | 
						|
                    } else if (token === 'extend') {
 | 
						|
                        this._parseExtend(topLevel, token);
 | 
						|
                    } else if (token === 'syntax') {
 | 
						|
                        this._parseIgnoredStatement(topLevel, token);
 | 
						|
                    } else {
 | 
						|
                        throw(new Error("Illegal top level declaration at line "+this.tn.line+": "+token));
 | 
						|
                    }
 | 
						|
                } while (true);
 | 
						|
                delete topLevel["name"];
 | 
						|
                return topLevel;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Parses a number value.
 | 
						|
             * @param {string} val Number value to parse
 | 
						|
             * @return {number} Number
 | 
						|
             * @throws {Error} If the number value is invalid
 | 
						|
             * @private
 | 
						|
             */
 | 
						|
            Parser.prototype._parseNumber = function(val) {
 | 
						|
                var sign = 1;
 | 
						|
                if (val.charAt(0) == '-') {
 | 
						|
                    sign = -1; val = val.substring(1);
 | 
						|
                }
 | 
						|
                if (Lang.NUMBER_DEC.test(val)) {
 | 
						|
                    return sign*parseInt(val, 10);
 | 
						|
                } else if (Lang.NUMBER_HEX.test(val)) {
 | 
						|
                    return sign*parseInt(val.substring(2), 16);
 | 
						|
                } else if (Lang.NUMBER_OCT.test(val)) {
 | 
						|
                    return sign*parseInt(val.substring(1), 8);
 | 
						|
                } else if (Lang.NUMBER_FLT.test(val)) {
 | 
						|
                    return sign*parseFloat(val);
 | 
						|
                }
 | 
						|
                throw(new Error("Illegal number value at line "+this.tn.line+": "+(sign < 0 ? '-' : '')+val));
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Parses an ID value.
 | 
						|
             * @param {string} val ID value to parse
 | 
						|
             * @param {boolean=} neg Whether the ID may be negative, defaults to `false`
 | 
						|
             * @returns {number} ID
 | 
						|
             * @throws {Error} If the ID value is invalid
 | 
						|
             * @private
 | 
						|
             */
 | 
						|
            Parser.prototype._parseId = function(val, neg) {
 | 
						|
                var id = -1;
 | 
						|
                var sign = 1;
 | 
						|
                if (val.charAt(0) == '-') {
 | 
						|
                    sign = -1; val = val.substring(1);
 | 
						|
                }
 | 
						|
                if (Lang.NUMBER_DEC.test(val)) {
 | 
						|
                    id = parseInt(val);
 | 
						|
                } else if (Lang.NUMBER_HEX.test(val)) {
 | 
						|
                    id = parseInt(val.substring(2), 16);
 | 
						|
                } else if (Lang.NUMBER_OCT.test(val)) {
 | 
						|
                    id = parseInt(val.substring(1), 8);
 | 
						|
                } else {
 | 
						|
                    throw(new Error("Illegal ID value at line "+this.tn.line+": "+(sign < 0 ? '-' : '')+val));
 | 
						|
                }
 | 
						|
                id = (sign*id)|0; // Force to 32bit
 | 
						|
                if (!neg && id < 0) {
 | 
						|
                    throw(new Error("Illegal ID range at line "+this.tn.line+": "+(sign < 0 ? '-' : '')+val));
 | 
						|
                }
 | 
						|
                return id;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Parses the package definition.
 | 
						|
             * @param {string} token Initial token
 | 
						|
             * @return {string} Package name
 | 
						|
             * @throws {Error} If the package definition cannot be parsed
 | 
						|
             * @private
 | 
						|
             */
 | 
						|
            Parser.prototype._parsePackage = function(token) {
 | 
						|
                token = this.tn.next();
 | 
						|
                if (!Lang.TYPEREF.test(token)) {
 | 
						|
                    throw(new Error("Illegal package name at line "+this.tn.line+": "+token));
 | 
						|
                }
 | 
						|
                var pkg = token;
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token != Lang.END) {
 | 
						|
                    throw(new Error("Illegal end of package definition at line "+this.tn.line+": "+token+" ('"+Lang.END+"' expected)"));
 | 
						|
                }
 | 
						|
                return pkg;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Parses an import definition.
 | 
						|
             * @param {string} token Initial token
 | 
						|
             * @return {string} Import file name 
 | 
						|
             * @throws {Error} If the import definition cannot be parsed
 | 
						|
             * @private
 | 
						|
             */
 | 
						|
            Parser.prototype._parseImport = function(token) {
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token === "public") {
 | 
						|
                    token = this.tn.next();
 | 
						|
                }
 | 
						|
                if (token !== Lang.STRINGOPEN) {
 | 
						|
                    throw(new Error("Illegal begin of import value at line "+this.tn.line+": "+token+" ('"+Lang.STRINGOPEN+"' expected)"));
 | 
						|
                }
 | 
						|
                var imported = this.tn.next();
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token !== Lang.STRINGCLOSE) {
 | 
						|
                    throw(new Error("Illegal end of import value at line "+this.tn.line+": "+token+" ('"+Lang.STRINGCLOSE+"' expected)"));
 | 
						|
                }
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token !== Lang.END) {
 | 
						|
                    throw(new Error("Illegal end of import definition at line "+this.tn.line+": "+token+" ('"+Lang.END+"' expected)"));
 | 
						|
                }
 | 
						|
                return imported;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Parses a namespace option.
 | 
						|
             * @param {Object} parent Parent definition
 | 
						|
             * @param {string} token Initial token
 | 
						|
             * @throws {Error} If the option cannot be parsed
 | 
						|
             * @private
 | 
						|
             */
 | 
						|
            Parser.prototype._parseOption = function(parent, token) {
 | 
						|
                token = this.tn.next();
 | 
						|
                var custom = false;
 | 
						|
                if (token == Lang.COPTOPEN) {
 | 
						|
                    custom = true;
 | 
						|
                    token = this.tn.next();
 | 
						|
                }
 | 
						|
                if (!Lang.NAME.test(token)) {
 | 
						|
                    // we can allow options of the form google.protobuf.* since they will just get ignored anyways
 | 
						|
                    if (!/google\.protobuf\./.test(token)) {
 | 
						|
                        throw(new Error("Illegal option name in message "+parent.name+" at line "+this.tn.line+": "+token));
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                var name = token;
 | 
						|
                token = this.tn.next();
 | 
						|
                if (custom) { // (my_method_option).foo, (my_method_option), some_method_option
 | 
						|
                    if (token !== Lang.COPTCLOSE) {
 | 
						|
                        throw(new Error("Illegal custom option name delimiter in message "+parent.name+", option "+name+" at line "+this.tn.line+": "+token+" ('"+Lang.COPTCLOSE+"' expected)"));
 | 
						|
                    }
 | 
						|
                    name = '('+name+')';
 | 
						|
                    token = this.tn.next();
 | 
						|
                    if (Lang.FQTYPEREF.test(token)) {
 | 
						|
                        name += token;
 | 
						|
                        token = this.tn.next();
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                if (token !== Lang.EQUAL) {
 | 
						|
                    throw(new Error("Illegal option operator in message "+parent.name+", option "+name+" at line "+this.tn.line+": "+token+" ('"+Lang.EQUAL+"' expected)"));
 | 
						|
                }
 | 
						|
                var value;
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token === Lang.STRINGOPEN) {
 | 
						|
                    value = this.tn.next();
 | 
						|
                    token = this.tn.next();
 | 
						|
                    if (token !== Lang.STRINGCLOSE) {
 | 
						|
                        throw(new Error("Illegal end of option value in message "+parent.name+", option "+name+" at line "+this.tn.line+": "+token+" ('"+Lang.STRINGCLOSE+"' expected)"));
 | 
						|
                    }
 | 
						|
                } else {
 | 
						|
                    if (Lang.NUMBER.test(token)) {
 | 
						|
                        value = this._parseNumber(token, true);
 | 
						|
                    } else if (Lang.TYPEREF.test(token)) {
 | 
						|
                        value = token;
 | 
						|
                    } else {
 | 
						|
                        throw(new Error("Illegal option value in message "+parent.name+", option "+name+" at line "+this.tn.line+": "+token));
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token !== Lang.END) {
 | 
						|
                    throw(new Error("Illegal end of option in message "+parent.name+", option "+name+" at line "+this.tn.line+": "+token+" ('"+Lang.END+"' expected)"));
 | 
						|
                }
 | 
						|
                parent["options"][name] = value;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Parses an ignored block of the form ['keyword', 'typeref', '{' ... '}'].
 | 
						|
             * @param {Object} parent Parent definition
 | 
						|
             * @param {string} keyword Initial token
 | 
						|
             * @throws {Error} If the directive cannot be parsed
 | 
						|
             * @private
 | 
						|
             */
 | 
						|
            Parser.prototype._parseIgnoredBlock = function(parent, keyword) {
 | 
						|
                var token = this.tn.next();
 | 
						|
                if (!Lang.TYPEREF.test(token)) {
 | 
						|
                    throw(new Error("Illegal "+keyword+" type in "+parent.name+": "+token));
 | 
						|
                }
 | 
						|
                var name = token;
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token !== Lang.OPEN) {
 | 
						|
                    throw(new Error("Illegal OPEN in "+parent.name+" after "+keyword+" "+name+" at line "+this.tn.line+": "+token));
 | 
						|
                }
 | 
						|
                var depth = 1;
 | 
						|
                do {
 | 
						|
                    token = this.tn.next();
 | 
						|
                    if (token === null) {
 | 
						|
                        throw(new Error("Unexpected EOF in "+parent.name+", "+keyword+" (ignored) at line "+this.tn.line+": "+name));
 | 
						|
                    }
 | 
						|
                    if (token === Lang.OPEN) {
 | 
						|
                        depth++;
 | 
						|
                    } else if (token === Lang.CLOSE) {
 | 
						|
                        token = this.tn.peek();
 | 
						|
                        if (token === Lang.END) this.tn.next();
 | 
						|
                        depth--;
 | 
						|
                        if (depth === 0) {
 | 
						|
                            break;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                } while(true);
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Parses an ignored statement of the form ['keyword', ..., ';'].
 | 
						|
             * @param {Object} parent Parent definition
 | 
						|
             * @param {string} keyword Initial token
 | 
						|
             * @throws {Error} If the directive cannot be parsed
 | 
						|
             * @private
 | 
						|
             */
 | 
						|
            Parser.prototype._parseIgnoredStatement = function(parent, keyword) {
 | 
						|
                var token;
 | 
						|
                do {
 | 
						|
                    token = this.tn.next();
 | 
						|
                    if (token === null) {
 | 
						|
                        throw(new Error("Unexpected EOF in "+parent.name+", "+keyword+" (ignored) at line "+this.tn.line));
 | 
						|
                    }
 | 
						|
                    if (token === Lang.END) break;
 | 
						|
                } while (true);
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Parses a service definition.
 | 
						|
             * @param {Object} parent Parent definition
 | 
						|
             * @param {string} keyword Initial token
 | 
						|
             * @throws {Error} If the service cannot be parsed
 | 
						|
             * @private
 | 
						|
             */
 | 
						|
            Parser.prototype._parseService = function(parent, keyword) {
 | 
						|
                var token = this.tn.next();
 | 
						|
                if (!Lang.NAME.test(token)) {
 | 
						|
                    throw(new Error("Illegal service name at line "+this.tn.line+": "+token));
 | 
						|
                }
 | 
						|
                var name = token;
 | 
						|
                var svc = {
 | 
						|
                    "name": name,
 | 
						|
                    "rpc": {},
 | 
						|
                    "options": {}
 | 
						|
                };
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token !== Lang.OPEN) {
 | 
						|
                    throw(new Error("Illegal OPEN after service "+name+" at line "+this.tn.line+": "+token+" ('"+Lang.OPEN+"' expected)"));
 | 
						|
                }
 | 
						|
                do {
 | 
						|
                    token = this.tn.next();
 | 
						|
                    if (token === "option") {
 | 
						|
                        this._parseOption(svc, token);
 | 
						|
                    } else if (token === 'rpc') {
 | 
						|
                        this._parseServiceRPC(svc, token);
 | 
						|
                    } else if (token !== Lang.CLOSE) {
 | 
						|
                        throw(new Error("Illegal type for service "+name+" at line "+this.tn.line+": "+token));
 | 
						|
                    }
 | 
						|
                } while (token !== Lang.CLOSE);
 | 
						|
                parent["services"].push(svc);
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Parses a RPC service definition of the form ['rpc', name, (request), 'returns', (response)].
 | 
						|
             * @param {Object} svc Parent definition
 | 
						|
             * @param {string} token Initial token
 | 
						|
             * @private
 | 
						|
             */
 | 
						|
            Parser.prototype._parseServiceRPC = function(svc, token) {
 | 
						|
                var type = token;
 | 
						|
                token = this.tn.next();
 | 
						|
                if (!Lang.NAME.test(token)) {
 | 
						|
                    throw(new Error("Illegal RPC method name in service "+svc["name"]+" at line "+this.tn.line+": "+token));
 | 
						|
                }
 | 
						|
                var name = token;
 | 
						|
                var method = {
 | 
						|
                    "request": null,
 | 
						|
                    "response": null,
 | 
						|
                    "options": {}
 | 
						|
                };
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token !== Lang.COPTOPEN) {
 | 
						|
                    throw(new Error("Illegal start of request type in RPC service "+svc["name"]+"#"+name+" at line "+this.tn.line+": "+token+" ('"+Lang.COPTOPEN+"' expected)"));
 | 
						|
                }
 | 
						|
                token = this.tn.next();
 | 
						|
                if (!Lang.TYPEREF.test(token)) {
 | 
						|
                    throw(new Error("Illegal request type in RPC service "+svc["name"]+"#"+name+" at line "+this.tn.line+": "+token));
 | 
						|
                }
 | 
						|
                method["request"] = token;
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token != Lang.COPTCLOSE) {
 | 
						|
                    throw(new Error("Illegal end of request type in RPC service "+svc["name"]+"#"+name+" at line "+this.tn.line+": "+token+" ('"+Lang.COPTCLOSE+"' expected)"))
 | 
						|
                }
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token.toLowerCase() !== "returns") {
 | 
						|
                    throw(new Error("Illegal request/response delimiter in RPC service "+svc["name"]+"#"+name+" at line "+this.tn.line+": "+token+" ('returns' expected)"));
 | 
						|
                }
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token != Lang.COPTOPEN) {
 | 
						|
                    throw(new Error("Illegal start of response type in RPC service "+svc["name"]+"#"+name+" at line "+this.tn.line+": "+token+" ('"+Lang.COPTOPEN+"' expected)"));
 | 
						|
                }
 | 
						|
                token = this.tn.next();
 | 
						|
                method["response"] = token;
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token !== Lang.COPTCLOSE) {
 | 
						|
                    throw(new Error("Illegal end of response type in RPC service "+svc["name"]+"#"+name+" at line "+this.tn.line+": "+token+" ('"+Lang.COPTCLOSE+"' expected)"))
 | 
						|
                }
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token === Lang.OPEN) {
 | 
						|
                    do {
 | 
						|
                        token = this.tn.next();
 | 
						|
                        if (token === 'option') {
 | 
						|
                            this._parseOption(method, token); // <- will fail for the custom-options example
 | 
						|
                        } else if (token !== Lang.CLOSE) {
 | 
						|
                            throw(new Error("Illegal start of option in RPC service "+svc["name"]+"#"+name+" at line "+this.tn.line+": "+token+" ('option' expected)"));
 | 
						|
                        }
 | 
						|
                    } while (token !== Lang.CLOSE);
 | 
						|
                } else if (token !== Lang.END) {
 | 
						|
                    throw(new Error("Illegal method delimiter in RPC service "+svc["name"]+"#"+name+" at line "+this.tn.line+": "+token+" ('"+Lang.END+"' or '"+Lang.OPEN+"' expected)"));
 | 
						|
                }
 | 
						|
                if (typeof svc[type] === 'undefined') svc[type] = {};
 | 
						|
                svc[type][name] = method;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Parses a message definition.
 | 
						|
             * @param {Object} parent Parent definition
 | 
						|
             * @param {string} token First token
 | 
						|
             * @return {Object}
 | 
						|
             * @throws {Error} If the message cannot be parsed
 | 
						|
             * @private
 | 
						|
             */
 | 
						|
            Parser.prototype._parseMessage = function(parent, token) {
 | 
						|
                /** @dict */
 | 
						|
                var msg = {}; // Note: At some point we might want to exclude the parser, so we need a dict.
 | 
						|
                token = this.tn.next();
 | 
						|
                if (!Lang.NAME.test(token)) {
 | 
						|
                    throw(new Error("Illegal message name"+(parent ? " in message "+parent["name"] : "")+" at line "+this.tn.line+": "+token));
 | 
						|
                }
 | 
						|
                msg["name"] = token;
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token != Lang.OPEN) {
 | 
						|
                    throw(new Error("Illegal OPEN after message "+msg.name+" at line "+this.tn.line+": "+token+" ('"+Lang.OPEN+"' expected)"));
 | 
						|
                }
 | 
						|
                msg["fields"] = []; // Note: Using arrays to support also browser that cannot preserve order of object keys.
 | 
						|
                msg["enums"] = [];
 | 
						|
                msg["messages"] = [];
 | 
						|
                msg["options"] = {};
 | 
						|
                // msg["extensions"] = undefined
 | 
						|
                do {
 | 
						|
                    token = this.tn.next();
 | 
						|
                    if (token === Lang.CLOSE) {
 | 
						|
                        token = this.tn.peek();
 | 
						|
                        if (token === Lang.END) this.tn.next();
 | 
						|
                        break;
 | 
						|
                    } else if (Lang.RULE.test(token)) {
 | 
						|
                        this._parseMessageField(msg, token);
 | 
						|
                    } else if (token === "enum") {
 | 
						|
                        this._parseEnum(msg, token);
 | 
						|
                    } else if (token === "message") {
 | 
						|
                        this._parseMessage(msg, token);
 | 
						|
                    } else if (token === "option") {
 | 
						|
                        this._parseOption(msg, token);
 | 
						|
                    } else if (token === "extensions") {
 | 
						|
                        msg["extensions"] = this._parseExtensions(msg, token);
 | 
						|
                    } else if (token === "extend") {
 | 
						|
                        this._parseExtend(msg, token);
 | 
						|
                    } else {
 | 
						|
                        throw(new Error("Illegal token in message "+msg.name+" at line "+this.tn.line+": "+token+" (type or '"+Lang.CLOSE+"' expected)"));
 | 
						|
                    }
 | 
						|
                } while (true);
 | 
						|
                parent["messages"].push(msg);
 | 
						|
                return msg;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Parses a message field.
 | 
						|
             * @param {Object} msg Message definition
 | 
						|
             * @param {string} token Initial token
 | 
						|
             * @throws {Error} If the message field cannot be parsed
 | 
						|
             * @private
 | 
						|
             */
 | 
						|
            Parser.prototype._parseMessageField = function(msg, token) {
 | 
						|
                /** @dict */
 | 
						|
                var fld = {};
 | 
						|
                fld["rule"] = token;
 | 
						|
                token = this.tn.next();
 | 
						|
                if (!Lang.TYPE.test(token) && !Lang.TYPEREF.test(token)) {
 | 
						|
                    throw(new Error("Illegal field type in message "+msg.name+" at line "+this.tn.line+": "+token));
 | 
						|
                }
 | 
						|
                fld["type"] = token;
 | 
						|
                token = this.tn.next();
 | 
						|
                if (!Lang.NAME.test(token)) {
 | 
						|
                    throw(new Error("Illegal field name in message "+msg.name+" at line "+this.tn.line+": "+token));
 | 
						|
                }
 | 
						|
                fld["name"] = token;
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token !== Lang.EQUAL) {
 | 
						|
                    throw(new Error("Illegal field number operator in message "+msg.name+"#"+fld.name+" at line "+this.tn.line+": "+token+" ('"+Lang.EQUAL+"' expected)"));
 | 
						|
                }
 | 
						|
                token = this.tn.next();
 | 
						|
                try {
 | 
						|
                    fld["id"] = this._parseId(token);
 | 
						|
                } catch (e) {
 | 
						|
                    throw(new Error("Illegal field id in message "+msg.name+"#"+fld.name+" at line "+this.tn.line+": "+token));
 | 
						|
                }
 | 
						|
                /** @dict */
 | 
						|
                fld["options"] = {};
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token === Lang.OPTOPEN) {
 | 
						|
                    this._parseFieldOptions(msg, fld, token);
 | 
						|
                    token = this.tn.next();
 | 
						|
                }
 | 
						|
                if (token !== Lang.END) {
 | 
						|
                    throw(new Error("Illegal field delimiter in message "+msg.name+"#"+fld.name+" at line "+this.tn.line+": "+token+" ('"+Lang.END+"' expected)"));
 | 
						|
                }
 | 
						|
                msg["fields"].push(fld);
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Parses a set of field option definitions.
 | 
						|
             * @param {Object} msg Message definition
 | 
						|
             * @param {Object} fld Field definition
 | 
						|
             * @param {string} token Initial token
 | 
						|
             * @throws {Error} If the message field options cannot be parsed
 | 
						|
             * @private
 | 
						|
             */
 | 
						|
            Parser.prototype._parseFieldOptions = function(msg, fld, token) {
 | 
						|
                var first = true;
 | 
						|
                do {
 | 
						|
                    token = this.tn.next();
 | 
						|
                    if (token === Lang.OPTCLOSE) {
 | 
						|
                        break;
 | 
						|
                    } else if (token === Lang.OPTEND) {
 | 
						|
                        if (first) {
 | 
						|
                            throw(new Error("Illegal start of message field options in message "+msg.name+"#"+fld.name+" at line "+this.tn.line+": "+token));
 | 
						|
                        }
 | 
						|
                        token = this.tn.next();
 | 
						|
                    }
 | 
						|
                    this._parseFieldOption(msg, fld, token);
 | 
						|
                    first = false;
 | 
						|
                } while (true);
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Parses a single field option.
 | 
						|
             * @param {Object} msg Message definition
 | 
						|
             * @param {Object} fld Field definition
 | 
						|
             * @param {string} token Initial token
 | 
						|
             * @throws {Error} If the mesage field option cannot be parsed
 | 
						|
             * @private
 | 
						|
             */
 | 
						|
            Parser.prototype._parseFieldOption = function(msg, fld, token) {
 | 
						|
                var custom = false;
 | 
						|
                if (token === Lang.COPTOPEN) {
 | 
						|
                    token = this.tn.next();
 | 
						|
                    custom = true;
 | 
						|
                }
 | 
						|
                if (!Lang.NAME.test(token)) {
 | 
						|
                    throw(new Error("Illegal field option in message "+msg.name+"#"+fld.name+" at line "+this.tn.line+": "+token));
 | 
						|
                }
 | 
						|
                var name = token;
 | 
						|
                token = this.tn.next();
 | 
						|
                if (custom) {
 | 
						|
                    if (token !== Lang.COPTCLOSE) {
 | 
						|
                        throw(new Error("Illegal custom field option name delimiter in message "+msg.name+"#"+fld.name+" at line "+this.tn.line+": "+token+" (')' expected)"));
 | 
						|
                    }
 | 
						|
                    name = '('+name+')';
 | 
						|
                    token = this.tn.next();
 | 
						|
                    if (Lang.FQTYPEREF.test(token)) {
 | 
						|
                        name += token;
 | 
						|
                        token = this.tn.next();
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                if (token !== Lang.EQUAL) {
 | 
						|
                    throw(new Error("Illegal field option operation in message "+msg.name+"#"+fld.name+" at line "+this.tn.line+": "+token+" ('=' expected)"));
 | 
						|
                }
 | 
						|
                var value;
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token === Lang.STRINGOPEN) {
 | 
						|
                    value = this.tn.next();
 | 
						|
                    token = this.tn.next();
 | 
						|
                    if (token != Lang.STRINGCLOSE) {
 | 
						|
                        throw(new Error("Illegal end of field value in message "+msg.name+"#"+fld.name+", option "+name+" at line "+this.tn.line+": "+token+" ('"+Lang.STRINGCLOSE+"' expected)"));
 | 
						|
                    }
 | 
						|
                } else if (Lang.NUMBER.test(token, true)) {
 | 
						|
                    value = this._parseNumber(token, true);
 | 
						|
                } else if (Lang.BOOL.test(token)) {
 | 
						|
                    value = token.toLowerCase() === 'true';
 | 
						|
                } else if (Lang.TYPEREF.test(token)) {
 | 
						|
                    value = token; // TODO: Resolve?
 | 
						|
                } else {
 | 
						|
                    throw(new Error("Illegal field option value in message "+msg.name+"#"+fld.name+", option "+name+" at line "+this.tn.line+": "+token));
 | 
						|
                }
 | 
						|
                fld["options"][name] = value;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Parses an enum.
 | 
						|
             * @param {Object} msg Message definition
 | 
						|
             * @param {string} token Initial token
 | 
						|
             * @throws {Error} If the enum cannot be parsed
 | 
						|
             * @private
 | 
						|
             */
 | 
						|
            Parser.prototype._parseEnum = function(msg, token) {
 | 
						|
                /** @dict */
 | 
						|
                var enm = {};
 | 
						|
                token = this.tn.next();
 | 
						|
                if (!Lang.NAME.test(token)) {
 | 
						|
                    throw(new Error("Illegal enum name in message "+msg.name+" at line "+this.tn.line+": "+token));
 | 
						|
                }
 | 
						|
                enm["name"] = token;
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token !== Lang.OPEN) {
 | 
						|
                    throw(new Error("Illegal OPEN after enum "+enm.name+" at line "+this.tn.line+": "+token));
 | 
						|
                }
 | 
						|
                enm["values"] = [];
 | 
						|
                enm["options"] = {};
 | 
						|
                do {
 | 
						|
                    token = this.tn.next();
 | 
						|
                    if (token === Lang.CLOSE) {
 | 
						|
                        token = this.tn.peek();
 | 
						|
                        if (token === Lang.END) this.tn.next();
 | 
						|
                        break;
 | 
						|
                    }
 | 
						|
                    if (token == 'option') {
 | 
						|
                        this._parseOption(enm, token);
 | 
						|
                    } else {
 | 
						|
                        if (!Lang.NAME.test(token)) {
 | 
						|
                            throw(new Error("Illegal enum value name in enum "+enm.name+" at line "+this.tn.line+": "+token));
 | 
						|
                        }
 | 
						|
                        this._parseEnumValue(enm, token);
 | 
						|
                    }
 | 
						|
                } while (true);
 | 
						|
                msg["enums"].push(enm);
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Parses an enum value.
 | 
						|
             * @param {Object} enm Enum definition
 | 
						|
             * @param {string} token Initial token
 | 
						|
             * @throws {Error} If the enum value cannot be parsed
 | 
						|
             * @private
 | 
						|
             */
 | 
						|
            Parser.prototype._parseEnumValue = function(enm, token) {
 | 
						|
                /** @dict */
 | 
						|
                var val = {};
 | 
						|
                val["name"] = token;
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token !== Lang.EQUAL) {
 | 
						|
                    throw(new Error("Illegal enum value operator in enum "+enm.name+" at line "+this.tn.line+": "+token+" ('"+Lang.EQUAL+"' expected)"));
 | 
						|
                }
 | 
						|
                token = this.tn.next();
 | 
						|
                try {
 | 
						|
                    val["id"] = this._parseId(token, true);
 | 
						|
                } catch (e) {
 | 
						|
                    throw(new Error("Illegal enum value id in enum "+enm.name+" at line "+this.tn.line+": "+token));
 | 
						|
                }
 | 
						|
                enm["values"].push(val);
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token === Lang.OPTOPEN) {
 | 
						|
                    var opt = { 'options' : {} }; // TODO: Actually expose them somehow.
 | 
						|
                    this._parseFieldOptions(enm, opt, token);
 | 
						|
                    token = this.tn.next();
 | 
						|
                }
 | 
						|
                if (token !== Lang.END) {
 | 
						|
                    throw(new Error("Illegal enum value delimiter in enum "+enm.name+" at line "+this.tn.line+": "+token+" ('"+Lang.END+"' expected)"));
 | 
						|
                }
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Parses an extensions statement.
 | 
						|
             * @param {Object} msg Message object
 | 
						|
             * @param {string} token Initial token
 | 
						|
             * @throws {Error} If the extensions statement cannot be parsed
 | 
						|
             * @private
 | 
						|
             */
 | 
						|
            Parser.prototype._parseExtensions = function(msg, token) {
 | 
						|
                /** @type {Array.<number>} */
 | 
						|
                var range = [];
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token === "min") { // FIXME: Does the official implementation support this?
 | 
						|
                    range.push(Lang.ID_MIN);
 | 
						|
                } else if (token === "max") {
 | 
						|
                    range.push(Lang.ID_MAX);
 | 
						|
                } else {
 | 
						|
                    range.push(this._parseNumber(token));
 | 
						|
                }
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token !== 'to') {
 | 
						|
                    throw("Illegal extensions delimiter in message "+msg.name+" at line "+this.tn.line+" ('to' expected)");
 | 
						|
                }
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token === "min") {
 | 
						|
                    range.push(Lang.ID_MIN);
 | 
						|
                } else if (token === "max") {
 | 
						|
                    range.push(Lang.ID_MAX);
 | 
						|
                } else {
 | 
						|
                    range.push(this._parseNumber(token));
 | 
						|
                }
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token !== Lang.END) {
 | 
						|
                    throw(new Error("Illegal extension delimiter in message "+msg.name+" at line "+this.tn.line+": "+token+" ('"+Lang.END+"' expected)"));
 | 
						|
                }
 | 
						|
                return range;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Parses an extend block.
 | 
						|
             * @param {Object} parent Parent object
 | 
						|
             * @param {string} token Initial token
 | 
						|
             * @throws {Error} If the extend block cannot be parsed
 | 
						|
             * @private
 | 
						|
             */
 | 
						|
            Parser.prototype._parseExtend = function(parent, token) {
 | 
						|
                token = this.tn.next();
 | 
						|
                if (!Lang.TYPEREF.test(token)) {
 | 
						|
                    throw(new Error("Illegal extended message name at line "+this.tn.line+": "+token));
 | 
						|
                }
 | 
						|
                /** @dict */
 | 
						|
                var ext = {};
 | 
						|
                ext["ref"] = token;
 | 
						|
                ext["fields"] = [];
 | 
						|
                token = this.tn.next();
 | 
						|
                if (token !== Lang.OPEN) {
 | 
						|
                    throw(new Error("Illegal OPEN in extend "+ext.name+" at line "+this.tn.line+": "+token+" ('"+Lang.OPEN+"' expected)"));
 | 
						|
                }
 | 
						|
                do {
 | 
						|
                    token = this.tn.next();
 | 
						|
                    if (token === Lang.CLOSE) {
 | 
						|
                        token = this.tn.peek();
 | 
						|
                        if (token == Lang.END) this.tn.next();
 | 
						|
                        break;
 | 
						|
                    } else if (Lang.RULE.test(token)) {
 | 
						|
                        this._parseMessageField(ext, token);
 | 
						|
                    } else {
 | 
						|
                        throw(new Error("Illegal token in extend "+ext.name+" at line "+this.tn.line+": "+token+" (rule or '"+Lang.CLOSE+"' expected)"));
 | 
						|
                    }
 | 
						|
                } while (true);
 | 
						|
                parent["messages"].push(ext);
 | 
						|
                return ext;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Returns a string representation of this object.
 | 
						|
             * @returns {string} String representation as of "Parser"
 | 
						|
             */
 | 
						|
            Parser.prototype.toString = function() {
 | 
						|
                return "Parser";
 | 
						|
            };
 | 
						|
            
 | 
						|
            return Parser;
 | 
						|
            
 | 
						|
        })(ProtoBuf, ProtoBuf.Lang, ProtoBuf.DotProto.Tokenizer);
 | 
						|
                        
 | 
						|
        /**
 | 
						|
         * @alias ProtoBuf.Reflect
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.Reflect = (function(ProtoBuf) {
 | 
						|
            "use strict";
 | 
						|
            
 | 
						|
            /**
 | 
						|
             * @exports ProtoBuf.Reflect
 | 
						|
             * @namespace
 | 
						|
             */
 | 
						|
            var Reflect = {};
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Constructs a Reflect base class.
 | 
						|
             * @exports ProtoBuf.Reflect.T
 | 
						|
             * @constructor
 | 
						|
             * @param {ProtoBuf.Reflect.T} parent Parent object
 | 
						|
             * @param {string} name Object name
 | 
						|
             */
 | 
						|
            var T = function(parent, name) {
 | 
						|
                /**
 | 
						|
                 * Parent object.
 | 
						|
                 * @type {ProtoBuf.Reflect.T|null}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.parent = parent;
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Object name in namespace.
 | 
						|
                 * @type {string}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.name = name;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Returns the fully qualified name of this object.
 | 
						|
             * @returns {string} Fully qualified name as of ".PATH.TO.THIS"
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            T.prototype.fqn = function() {
 | 
						|
                var name = this.name,
 | 
						|
                    ptr = this;
 | 
						|
                do {
 | 
						|
                    ptr = ptr.parent;
 | 
						|
                    if (ptr == null) break;
 | 
						|
                    name = ptr.name+"."+name;
 | 
						|
                } while (true);
 | 
						|
                return name;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Returns a string representation of this Reflect object (its fully qualified name).
 | 
						|
             * @param {boolean=} includeClass Set to true to include the class name. Defaults to false.
 | 
						|
             * @return String representation
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            T.prototype.toString = function(includeClass) {
 | 
						|
                var name = this.fqn();
 | 
						|
                if (includeClass) {
 | 
						|
                    if (this instanceof Message) {
 | 
						|
                        name = "Message "+name;
 | 
						|
                    } else if (this instanceof Message.Field) {
 | 
						|
                        name = "Message.Field "+name;
 | 
						|
                    } else if (this instanceof Enum) {
 | 
						|
                        name = "Enum "+name;
 | 
						|
                    } else if (this instanceof Enum.Value) {
 | 
						|
                        name = "Enum.Value "+name;
 | 
						|
                    } else if (this instanceof Service) {
 | 
						|
                        name = "Service "+name;
 | 
						|
                    } else if (this instanceof Service.Method) {
 | 
						|
                        if (this instanceof Service.RPCMethod) {
 | 
						|
                            name = "Service.RPCMethod "+name;
 | 
						|
                        } else {
 | 
						|
                            name = "Service.Method "+name; // Should not happen as it is abstract
 | 
						|
                        }
 | 
						|
                    } else if (this instanceof Namespace) {
 | 
						|
                        name = "Namespace "+name;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                return name;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Builds this type.
 | 
						|
             * @throws {Error} If this type cannot be built directly
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            T.prototype.build = function() {
 | 
						|
                throw(new Error(this.toString(true)+" cannot be built directly"));
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * @alias ProtoBuf.Reflect.T
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Reflect.T = T;
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Constructs a new Namespace.
 | 
						|
             * @exports ProtoBuf.Reflect.Namespace
 | 
						|
             * @param {ProtoBuf.Reflect.Namespace|null} parent Namespace parent
 | 
						|
             * @param {string} name Namespace name
 | 
						|
             * @param {Object.<string,*>} options Namespace options
 | 
						|
             * @constructor
 | 
						|
             * @extends ProtoBuf.Reflect.T
 | 
						|
             */
 | 
						|
            var Namespace = function(parent, name, options) {
 | 
						|
                T.call(this, parent, name);
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Children inside the namespace.
 | 
						|
                 * @type {Array.<ProtoBuf.Reflect.T>}
 | 
						|
                 */
 | 
						|
                this.children = [];
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Options.
 | 
						|
                 * @type {Object.<string, *>}
 | 
						|
                 */
 | 
						|
                this.options = options || {};
 | 
						|
            };
 | 
						|
        
 | 
						|
            // Extends T
 | 
						|
            Namespace.prototype = Object.create(T.prototype);
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Returns an array of the namespace's children.
 | 
						|
             * @param {ProtoBuf.Reflect.T=} type Filter type (returns instances of this type only). Defaults to null (all children).
 | 
						|
             * @return {Array.<ProtoBuf.Reflect.T>}
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Namespace.prototype.getChildren = function(type) {
 | 
						|
                type = type || null;
 | 
						|
                if (type == null) {
 | 
						|
                    return this.children.slice();
 | 
						|
                }
 | 
						|
                var children = [];
 | 
						|
                for (var i=0; i<this.children.length; i++) {
 | 
						|
                    if (this.children[i] instanceof type) {
 | 
						|
                        children.push(this.children[i]);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                return children;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Adds a child to the namespace.
 | 
						|
             * @param {ProtoBuf.Reflect.T} child Child
 | 
						|
             * @throws {Error} If the child cannot be added (duplicate)
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Namespace.prototype.addChild = function(child) {
 | 
						|
                var other;
 | 
						|
                if (other = this.getChild(child.name)) {
 | 
						|
                    // Try to revert camelcase transformation on collision
 | 
						|
                    if (other instanceof Message.Field && other.name !== other.originalName && !this.hasChild(other.originalName)) {
 | 
						|
                        other.name = other.originalName; // Revert previous first (effectively keeps both originals)
 | 
						|
                    } else if (child instanceof Message.Field && child.name !== child.originalName && !this.hasChild(child.originalName)) {
 | 
						|
                        child.name = child.originalName;
 | 
						|
                    } else {
 | 
						|
                        throw(new Error("Duplicate name in namespace "+this.toString(true)+": "+child.name));
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                this.children.push(child);
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Tests if this namespace has a child with the specified name.
 | 
						|
             * @param {string|number} nameOrId Child name or id
 | 
						|
             * @returns {boolean} true if there is one, else false
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Namespace.prototype.hasChild = function(nameOrId) {
 | 
						|
                var i;
 | 
						|
                if (typeof nameOrId == 'number') {
 | 
						|
                    for (i=0; i<this.children.length; i++) if (typeof this.children[i].id !== 'undefined' && this.children[i].id == nameOrId) return true;
 | 
						|
                } else {
 | 
						|
                    for (i=0; i<this.children.length; i++) if (typeof this.children[i].name !== 'undefined' && this.children[i].name == nameOrId) return true;
 | 
						|
                }
 | 
						|
                return false;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Gets a child by its name.
 | 
						|
             * @param {string|number} nameOrId Child name or id
 | 
						|
             * @return {?ProtoBuf.Reflect.T} The child or null if not found
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Namespace.prototype.getChild = function(nameOrId) {
 | 
						|
                var i;
 | 
						|
                if (typeof nameOrId == 'number') {
 | 
						|
                    for (i=0; i<this.children.length; i++) if (typeof this.children[i].id !== 'undefined' && this.children[i].id == nameOrId) return this.children[i];
 | 
						|
                } else {
 | 
						|
                    for (i=0; i<this.children.length; i++) if (typeof this.children[i].name !== 'undefined' && this.children[i].name == nameOrId) return this.children[i];
 | 
						|
                }
 | 
						|
                return null;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Resolves a reflect object inside of this namespace.
 | 
						|
             * @param {string} qn Qualified name to resolve
 | 
						|
             * @param {boolean=} excludeFields Excludes fields, defaults to `false`
 | 
						|
             * @return {ProtoBuf.Reflect.Namespace|null} The resolved type or null if not found
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Namespace.prototype.resolve = function(qn, excludeFields) {
 | 
						|
                var part = qn.split(".");
 | 
						|
                var ptr = this, i=0;
 | 
						|
                if (part[i] == "") { // Fully qualified name, e.g. ".My.Message'
 | 
						|
                    while (ptr.parent != null) {
 | 
						|
                        ptr = ptr.parent;
 | 
						|
                    }
 | 
						|
                    i++;
 | 
						|
                }
 | 
						|
                var child;
 | 
						|
                do {
 | 
						|
                    do {
 | 
						|
                        child = ptr.getChild(part[i]);
 | 
						|
                        if (!child || !(child instanceof Reflect.T) || (excludeFields && child instanceof Reflect.Message.Field)) {
 | 
						|
                            ptr = null;
 | 
						|
                            break;
 | 
						|
                        }
 | 
						|
                        ptr = child; i++;
 | 
						|
                    } while (i < part.length);
 | 
						|
                    if (ptr != null) break; // Found
 | 
						|
                    // Else search the parent
 | 
						|
                    if (this.parent !== null) {
 | 
						|
                        return this.parent.resolve(qn, excludeFields);
 | 
						|
                    }
 | 
						|
                } while (ptr != null);
 | 
						|
                return ptr;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Builds the namespace and returns the runtime counterpart.
 | 
						|
             * @return {Object.<string,Function|Object>} Runtime namespace
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Namespace.prototype.build = function() {
 | 
						|
                /** @dict */
 | 
						|
                var ns = {};
 | 
						|
                var children = this.getChildren(), child;
 | 
						|
                for (var i=0; i<children.length; i++) {
 | 
						|
                    child = children[i];
 | 
						|
                    if (child instanceof Namespace) {
 | 
						|
                        ns[child.name] = child.build();
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                if (Object.defineProperty) {
 | 
						|
                    Object.defineProperty(ns, "$options", {
 | 
						|
                        "value": this.buildOpt(),
 | 
						|
                        "enumerable": false,
 | 
						|
                        "configurable": false,
 | 
						|
                        "writable": false
 | 
						|
                    });
 | 
						|
                }
 | 
						|
                return ns;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Builds the namespace's '$options' property.
 | 
						|
             * @return {Object.<string,*>}
 | 
						|
             */
 | 
						|
            Namespace.prototype.buildOpt = function() {
 | 
						|
                var opt = {};
 | 
						|
                var keys = Object.keys(this.options);
 | 
						|
                for (var i=0; i<keys.length; i++) {
 | 
						|
                    var key = keys[i];
 | 
						|
                    var val = this.options[keys[i]];
 | 
						|
                    // TODO: Options are not resolved, yet.
 | 
						|
                    // if (val instanceof Namespace) {
 | 
						|
                    //     opt[key] = val.build();
 | 
						|
                    // } else {
 | 
						|
                        opt[key] = val;
 | 
						|
                    // }
 | 
						|
                }
 | 
						|
                return opt;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Gets the value assigned to the option with the specified name.
 | 
						|
             * @param {string=} name Returns the option value if specified, otherwise all options are returned.
 | 
						|
             * @return {*|Object.<string,*>}null} Option value or NULL if there is no such option
 | 
						|
             */
 | 
						|
            Namespace.prototype.getOption = function(name) {
 | 
						|
                if (typeof name == 'undefined') {
 | 
						|
                    return this.options;
 | 
						|
                }
 | 
						|
                return typeof this.options[name] != 'undefined' ? this.options[name] : null;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * @alias ProtoBuf.Reflect.Namespace
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Reflect.Namespace = Namespace;
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Constructs a new Message.
 | 
						|
             * @exports ProtoBuf.Reflect.Message
 | 
						|
             * @param {ProtoBuf.Reflect.Namespace} parent Parent message or namespace
 | 
						|
             * @param {string} name Message name
 | 
						|
             * @param {Object.<string,*>} options Message options
 | 
						|
             * @constructor
 | 
						|
             * @extends ProtoBuf.Reflect.Namespace
 | 
						|
             */
 | 
						|
            var Message = function(parent, name, options) {
 | 
						|
                Namespace.call(this, parent, name, options);
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Extensions range.
 | 
						|
                 * @type {!Array.<number>}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.extensions = [ProtoBuf.Lang.ID_MIN, ProtoBuf.Lang.ID_MAX];
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Runtime message class.
 | 
						|
                 * @type {?function(new:ProtoBuf.Builder.Message)}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.clazz = null;
 | 
						|
            };
 | 
						|
        
 | 
						|
            // Extends Namespace
 | 
						|
            Message.prototype = Object.create(Namespace.prototype);
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Builds the message and returns the runtime counterpart, which is a fully functional class.
 | 
						|
             * @see ProtoBuf.Builder.Message
 | 
						|
             * @param {boolean=} rebuild Whether to rebuild or not, defaults to false
 | 
						|
             * @return {ProtoBuf.Reflect.Message} Message class
 | 
						|
             * @throws {Error} If the message cannot be built
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Message.prototype.build = function(rebuild) {
 | 
						|
                if (this.clazz && !rebuild) return this.clazz;
 | 
						|
                
 | 
						|
                // We need to create a prototyped Message class in an isolated scope
 | 
						|
                var clazz = (function(ProtoBuf, T) {
 | 
						|
                    var fields = T.getChildren(Reflect.Message.Field);
 | 
						|
        
 | 
						|
                    /**
 | 
						|
                     * Constructs a new runtime Message.
 | 
						|
                     * @name ProtoBuf.Builder.Message
 | 
						|
                     * @class Barebone of all runtime messages.
 | 
						|
                     * @param {Object.<string,*>|...[string]} values Preset values
 | 
						|
                     * @constructor
 | 
						|
                     * @throws {Error} If the message cannot be created
 | 
						|
                     */
 | 
						|
                    var Message = function(values) {
 | 
						|
                        ProtoBuf.Builder.Message.call(this);
 | 
						|
                        var i, field;
 | 
						|
        
 | 
						|
                        // Create fields on the object itself to allow setting and getting through Message#fieldname
 | 
						|
                        for (i=0; i<fields.length; i++) {
 | 
						|
                            field = fields[i];
 | 
						|
                            this[field.name] = (field.repeated) ? [] : null;
 | 
						|
                        }
 | 
						|
                        // Set the default values
 | 
						|
                        for (i=0; i<fields.length; i++) {
 | 
						|
                            field = fields[i];
 | 
						|
                            if (typeof field.options['default'] != 'undefined') {
 | 
						|
                                try {
 | 
						|
                                    this.set(field.name, field.options['default']); // Should not throw
 | 
						|
                                } catch (e) {
 | 
						|
                                    throw(new Error("[INTERNAL] "+e));
 | 
						|
                                }
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                        // Set field values from a values object
 | 
						|
                        if (arguments.length == 1 && typeof values == 'object' &&
 | 
						|
                            /* not another Message */ typeof values.encode != 'function' &&
 | 
						|
                            /* not a repeated field */ !ProtoBuf.Util.isArray(values) &&
 | 
						|
                            /* not a ByteBuffer */ !(values instanceof ByteBuffer) &&
 | 
						|
                            /* not an ArrayBuffer */ !(values instanceof ArrayBuffer) &&
 | 
						|
                            /* not a Long */ !(ProtoBuf.Long && values instanceof ProtoBuf.Long)) {
 | 
						|
                            var keys = Object.keys(values);
 | 
						|
                            for (i=0; i<keys.length; i++) {
 | 
						|
                                this.set(keys[i], values[keys[i]]); // May throw
 | 
						|
                            }
 | 
						|
                            // Else set field values from arguments, in correct order
 | 
						|
                        } else {
 | 
						|
                            for (i=0; i<arguments.length; i++) {
 | 
						|
                                if (i<fields.length) {
 | 
						|
                                    this.set(fields[i].name, arguments[i]); // May throw
 | 
						|
                                }
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    };
 | 
						|
        
 | 
						|
                    // Extends ProtoBuf.Builder.Message
 | 
						|
                    Message.prototype = Object.create(ProtoBuf.Builder.Message.prototype);
 | 
						|
        
 | 
						|
                    /**
 | 
						|
                     * Adds a value to a repeated field.
 | 
						|
                     * @name ProtoBuf.Builder.Message#add
 | 
						|
                     * @function
 | 
						|
                     * @param {string} key Field name
 | 
						|
                     * @param {*} value Value to add
 | 
						|
                     * @throws {Error} If the value cannot be added
 | 
						|
                     * @expose
 | 
						|
                     */
 | 
						|
                    Message.prototype.add = function(key, value) {
 | 
						|
                        var field = T.getChild(key);
 | 
						|
                        if (!field) {
 | 
						|
                            throw(new Error(this+"#"+key+" is undefined"));
 | 
						|
                        }
 | 
						|
                        if (!(field instanceof ProtoBuf.Reflect.Message.Field)) {
 | 
						|
                            throw(new Error(this+"#"+key+" is not a field: "+field.toString(true))); // May throw if it's an enum or embedded message
 | 
						|
                        }
 | 
						|
                        if (!field.repeated) {
 | 
						|
                            throw(new Error(this+"#"+key+" is not a repeated field"));
 | 
						|
                        }
 | 
						|
                        if (this[field.name] === null) this[field.name] = [];
 | 
						|
                        this[field.name].push(field.verifyValue(value, true));
 | 
						|
                    };
 | 
						|
        
 | 
						|
                    /**
 | 
						|
                     * Sets a field value.
 | 
						|
                     * @name ProtoBuf.Builder.Message#set
 | 
						|
                     * @function
 | 
						|
                     * @param {string} key Key
 | 
						|
                     * @param {*} value Value to set
 | 
						|
                     * @throws {Error} If the value cannot be set
 | 
						|
                     * @expose
 | 
						|
                     */
 | 
						|
                    Message.prototype.set = function(key, value) {
 | 
						|
                        var field = T.getChild(key);
 | 
						|
                        if (!field) {
 | 
						|
                            throw(new Error(this+"#"+key+" is not a field: undefined"));
 | 
						|
                        }
 | 
						|
                        if (!(field instanceof ProtoBuf.Reflect.Message.Field)) {
 | 
						|
                            throw(new Error(this+"#"+key+" is not a field: "+field.toString(true)));
 | 
						|
                        }
 | 
						|
                        this[field.name] = field.verifyValue(value); // May throw
 | 
						|
                    };
 | 
						|
        
 | 
						|
                    /**
 | 
						|
                     * Gets a value.
 | 
						|
                     * @name ProtoBuf.Builder.Message#get
 | 
						|
                     * @function
 | 
						|
                     * @param {string} key Key
 | 
						|
                     * @return {*} Value
 | 
						|
                     * @throws {Error} If there is no such field
 | 
						|
                     * @expose
 | 
						|
                     */
 | 
						|
                    Message.prototype.get = function(key) {
 | 
						|
                        var field = T.getChild(key);
 | 
						|
                        if (!field || !(field instanceof ProtoBuf.Reflect.Message.Field)) {
 | 
						|
                            throw(new Error(this+"#"+key+" is not a field: undefined"));
 | 
						|
                        }
 | 
						|
                        if (!(field instanceof ProtoBuf.Reflect.Message.Field)) {
 | 
						|
                            throw(new Error(this+"#"+key+" is not a field: "+field.toString(true)));
 | 
						|
                        }
 | 
						|
                        return this[field.name];
 | 
						|
                    };
 | 
						|
        
 | 
						|
                    // Getters and setters
 | 
						|
        
 | 
						|
                    for (var i=0; i<fields.length; i++) {
 | 
						|
                        var field = fields[i];
 | 
						|
                        
 | 
						|
                        (function(field) {
 | 
						|
                            // set/get[SomeValue]
 | 
						|
                            var Name = field.originalName.replace(/(_[a-zA-Z])/g,
 | 
						|
                                function(match) {
 | 
						|
                                    return match.toUpperCase().replace('_','');
 | 
						|
                                }
 | 
						|
                            );
 | 
						|
                            Name = Name.substring(0,1).toUpperCase()+Name.substring(1);
 | 
						|
            
 | 
						|
                            // set/get_[some_value]
 | 
						|
                            var name = field.originalName.replace(/([A-Z])/g,
 | 
						|
                                function(match) {
 | 
						|
                                    return "_"+match;
 | 
						|
                                }
 | 
						|
                            );
 | 
						|
            
 | 
						|
                            /**
 | 
						|
                             * Sets a value. This method is present for each field, but only if there is no name conflict with
 | 
						|
                             * another field.
 | 
						|
                             * @name ProtoBuf.Builder.Message#set[SomeField]
 | 
						|
                             * @function
 | 
						|
                             * @param {*} value Value to set
 | 
						|
                             * @abstract
 | 
						|
                             * @throws {Error} If the value cannot be set
 | 
						|
                             */
 | 
						|
                            if (!T.hasChild("set"+Name)) {
 | 
						|
                                Message.prototype["set"+Name] = function(value) {
 | 
						|
                                    this.set(field.name, value);
 | 
						|
                                }
 | 
						|
                            }
 | 
						|
            
 | 
						|
                            /**
 | 
						|
                             * Sets a value. This method is present for each field, but only if there is no name conflict with
 | 
						|
                             * another field.
 | 
						|
                             * @name ProtoBuf.Builder.Message#set_[some_field]
 | 
						|
                             * @function
 | 
						|
                             * @param {*} value Value to set
 | 
						|
                             * @abstract
 | 
						|
                             * @throws {Error} If the value cannot be set
 | 
						|
                             */
 | 
						|
                            if (!T.hasChild("set_"+name)) {
 | 
						|
                                Message.prototype["set_"+name] = function(value) {
 | 
						|
                                    this.set(field.name, value);
 | 
						|
                                };
 | 
						|
                            }
 | 
						|
            
 | 
						|
                            /**
 | 
						|
                             * Gets a value. This method is present for each field, but only if there is no name conflict with
 | 
						|
                             * another field.
 | 
						|
                             * @name ProtoBuf.Builder.Message#get[SomeField]
 | 
						|
                             * @function
 | 
						|
                             * @abstract
 | 
						|
                             * @return {*} The value
 | 
						|
                             */
 | 
						|
                            if (!T.hasChild("get"+Name)) {
 | 
						|
                                Message.prototype["get"+Name] = function() {
 | 
						|
                                    return this.get(field.name); // Does not throw, field exists
 | 
						|
                                }
 | 
						|
                            }
 | 
						|
            
 | 
						|
                            /**
 | 
						|
                             * Gets a value. This method is present for each field, but only if there is no name conflict with
 | 
						|
                             * another field.
 | 
						|
                             * @name ProtoBuf.Builder.Message#get_[some_field]
 | 
						|
                             * @function
 | 
						|
                             * @return {*} The value
 | 
						|
                             * @abstract
 | 
						|
                             */
 | 
						|
                            if (!T.hasChild("get_"+name)) {
 | 
						|
                                Message.prototype["get_"+name] = function() {
 | 
						|
                                    return this.get(field.name); // Does not throw, field exists
 | 
						|
                                };
 | 
						|
                            }
 | 
						|
                            
 | 
						|
                        })(field);
 | 
						|
                    }
 | 
						|
        
 | 
						|
                    // En-/decoding
 | 
						|
        
 | 
						|
                    /**
 | 
						|
                     * Encodes the message.
 | 
						|
                     * @name ProtoBuf.Builder.Message#encode
 | 
						|
                     * @function
 | 
						|
                     * @param {(!ByteBuffer|boolean)=} buffer ByteBuffer to encode to. Will create a new one if omitted.
 | 
						|
                     * @return {!ByteBuffer} Encoded message as a ByteBuffer
 | 
						|
                     * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
 | 
						|
                     *  returns the encoded ByteBuffer in the `encoded` property on the error.
 | 
						|
                     * @expose
 | 
						|
                     * @see ProtoBuf.Builder.Message#encode64
 | 
						|
                     * @see ProtoBuf.Builder.Message#encodeHex
 | 
						|
                     * @see ProtoBuf.Builder.Message#encodeAB
 | 
						|
                     */
 | 
						|
                    Message.prototype.encode = function(buffer) {
 | 
						|
                        buffer = buffer || new ByteBuffer();
 | 
						|
                        var le = buffer.littleEndian;
 | 
						|
                        try {
 | 
						|
                            return T.encode(this, buffer.LE()).flip().LE(le);
 | 
						|
                        } catch (e) {
 | 
						|
                            buffer.LE(le);
 | 
						|
                            throw(e);
 | 
						|
                        }
 | 
						|
                    };
 | 
						|
        
 | 
						|
                    /**
 | 
						|
                     * Directly encodes the message to an ArrayBuffer.
 | 
						|
                     * @name ProtoBuf.Builder.Message#encodeAB
 | 
						|
                     * @function
 | 
						|
                     * @return {ArrayBuffer} Encoded message as ArrayBuffer
 | 
						|
                     * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
 | 
						|
                     *  returns the encoded ArrayBuffer in the `encoded` property on the error.
 | 
						|
                     * @expose
 | 
						|
                     */
 | 
						|
                    Message.prototype.encodeAB = function() {
 | 
						|
                        var enc;
 | 
						|
                        try {
 | 
						|
                            return this.encode().toArrayBuffer();
 | 
						|
                        } catch (err) {
 | 
						|
                            if (err["encoded"]) err["encoded"] = err["encoded"].toArrayBuffer();
 | 
						|
                            throw(err);
 | 
						|
                        }
 | 
						|
                    };
 | 
						|
        
 | 
						|
                    /**
 | 
						|
                     * Returns the message as an ArrayBuffer. This is an alias for {@link ProtoBuf.Builder.Message#encodeAB}.
 | 
						|
                     * @name ProtoBuf.Builder.Message#toArrayBuffer
 | 
						|
                     * @function
 | 
						|
                     * @return {ArrayBuffer} Encoded message as ArrayBuffer
 | 
						|
                     * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
 | 
						|
                     *  returns the encoded ArrayBuffer in the `encoded` property on the error.
 | 
						|
                     * @expose
 | 
						|
                     */
 | 
						|
                    Message.prototype.toArrayBuffer = Message.prototype.encodeAB;
 | 
						|
        
 | 
						|
                    /**
 | 
						|
                     * Directly encodes the message to a node Buffer.
 | 
						|
                     * @name ProtoBuf.Builder.Message#encodeNB
 | 
						|
                     * @function
 | 
						|
                     * @return {!Buffer}
 | 
						|
                     * @throws {Error} If the message cannot be encoded, not running under node.js or if required fields are
 | 
						|
                     *  missing. The later still returns the encoded node Buffer in the `encoded` property on the error.
 | 
						|
                     * @expose
 | 
						|
                     */
 | 
						|
                    Message.prototype.encodeNB = function() {
 | 
						|
                        try {
 | 
						|
                            return this.encode().toBuffer();
 | 
						|
                        } catch (err) {
 | 
						|
                            if (err["encoded"]) err["encoded"] = err["encoded"].toBuffer();
 | 
						|
                            throw(err);
 | 
						|
                        }
 | 
						|
                    };
 | 
						|
        
 | 
						|
                    /**
 | 
						|
                     * Returns the message as a node Buffer. This is an alias for {@link ProtoBuf.Builder.Message#encodeNB}.
 | 
						|
                     * @name ProtoBuf.Builder.Message#encodeNB
 | 
						|
                     * @function
 | 
						|
                     * @return {!Buffer}
 | 
						|
                     * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
 | 
						|
                     *  returns the encoded node Buffer in the `encoded` property on the error.
 | 
						|
                     * @expose
 | 
						|
                     */
 | 
						|
                    Message.prototype.toBuffer = Message.prototype.encodeNB;
 | 
						|
        
 | 
						|
                    /**
 | 
						|
                     * Directly encodes the message to a base64 encoded string.
 | 
						|
                     * @name ProtoBuf.Builder.Message#encode64
 | 
						|
                     * @function
 | 
						|
                     * @return {string} Base64 encoded string
 | 
						|
                     * @throws {Error} If the underlying buffer cannot be encoded or if required fields are missing. The later
 | 
						|
                     *  still returns the encoded base64 string in the `encoded` property on the error.
 | 
						|
                     * @expose
 | 
						|
                     */
 | 
						|
                    Message.prototype.encode64 = function() {
 | 
						|
                        try {
 | 
						|
                            return this.encode().toBase64();
 | 
						|
                        } catch (err) {
 | 
						|
                            if (err["encoded"]) err["encoded"] = err["encoded"].toBase64();
 | 
						|
                            throw(err);
 | 
						|
                        }
 | 
						|
                    };
 | 
						|
        
 | 
						|
                    /**
 | 
						|
                     * Returns the message as a base64 encoded string. This is an alias for {@link ProtoBuf.Builder.Message#encode64}.
 | 
						|
                     * @name ProtoBuf.Builder.Message#toBase64
 | 
						|
                     * @function
 | 
						|
                     * @return {string} Base64 encoded string
 | 
						|
                     * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
 | 
						|
                     *  returns the encoded base64 string in the `encoded` property on the error.
 | 
						|
                     * @expose
 | 
						|
                     */
 | 
						|
                    Message.prototype.toBase64 = Message.prototype.encode64;
 | 
						|
        
 | 
						|
                    /**
 | 
						|
                     * Directly encodes the message to a hex encoded string.
 | 
						|
                     * @name ProtoBuf.Builder.Message#encodeHex
 | 
						|
                     * @function
 | 
						|
                     * @return {string} Hex encoded string
 | 
						|
                     * @throws {Error} If the underlying buffer cannot be encoded or if required fields are missing. The later
 | 
						|
                     *  still returns the encoded hex string in the `encoded` property on the error.
 | 
						|
                     * @expose
 | 
						|
                     */
 | 
						|
                    Message.prototype.encodeHex = function() {
 | 
						|
                        try {
 | 
						|
                            return this.encode().toHex();
 | 
						|
                        } catch (err) {
 | 
						|
                            if (err["encoded"]) err["encoded"] = err["encoded"].toHex();
 | 
						|
                            throw(err);
 | 
						|
                        }
 | 
						|
                    };
 | 
						|
        
 | 
						|
                    /**
 | 
						|
                     * Returns the message as a hex encoded string. This is an alias for {@link ProtoBuf.Builder.Message#encodeHex}.
 | 
						|
                     * @name ProtoBuf.Builder.Message#toHex
 | 
						|
                     * @function
 | 
						|
                     * @return {string} Hex encoded string
 | 
						|
                     * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
 | 
						|
                     *  returns the encoded hex string in the `encoded` property on the error.
 | 
						|
                     * @expose
 | 
						|
                     */
 | 
						|
                    Message.prototype.toHex = Message.prototype.encodeHex;
 | 
						|
        
 | 
						|
                    /**
 | 
						|
                     * Decodes the message from the specified buffer or string.
 | 
						|
                     * @name ProtoBuf.Builder.Message.decode
 | 
						|
                     * @function
 | 
						|
                     * @param {!ByteBuffer|!ArrayBuffer|!Buffer|string} buffer Buffer to decode from
 | 
						|
                     * @param {string=} enc Encoding if buffer is a string: hex, utf8 (not recommended), defaults to base64
 | 
						|
                     * @return {!ProtoBuf.Builder.Message} Decoded message
 | 
						|
                     * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still
 | 
						|
                     *  returns the decoded message with missing fields in the `decoded` property on the error.
 | 
						|
                     * @expose
 | 
						|
                     * @see ProtoBuf.Builder.Message.decode64
 | 
						|
                     * @see ProtoBuf.Builder.Message.decodeHex
 | 
						|
                     */
 | 
						|
                    Message.decode = function(buffer, enc) {
 | 
						|
                        if (buffer === null) throw(new Error("buffer must not be null"));
 | 
						|
                        if (typeof buffer === 'string') {
 | 
						|
                            buffer = ByteBuffer.wrap(buffer, enc ? enc : "base64");
 | 
						|
                        }
 | 
						|
                        buffer = buffer instanceof ByteBuffer ? buffer : ByteBuffer.wrap(buffer); // May throw
 | 
						|
                        var le = buffer.littleEndian;
 | 
						|
                        try {
 | 
						|
                            var msg = T.decode(buffer.LE());
 | 
						|
                            buffer.LE(le);
 | 
						|
                            return msg;
 | 
						|
                        } catch (e) {
 | 
						|
                            buffer.LE(le);
 | 
						|
                            throw(e);
 | 
						|
                        }
 | 
						|
                    };
 | 
						|
        
 | 
						|
                    /**
 | 
						|
                     * Decodes the message from the specified base64 encoded string.
 | 
						|
                     * @name ProtoBuf.Builder.Message.decode64
 | 
						|
                     * @function
 | 
						|
                     * @param {string} str String to decode from
 | 
						|
                     * @return {!ProtoBuf.Builder.Message} Decoded message
 | 
						|
                     * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still
 | 
						|
                     *  returns the decoded message with missing fields in the `decoded` property on the error.
 | 
						|
                     * @expose
 | 
						|
                     */
 | 
						|
                    Message.decode64 = function(str) {
 | 
						|
                        return Message.decode(str, "base64");
 | 
						|
                    };
 | 
						|
        
 | 
						|
                    /**
 | 
						|
                     * Decodes the message from the specified hex encoded string.
 | 
						|
                     * @name ProtoBuf.Builder.Message.decodeHex
 | 
						|
                     * @function
 | 
						|
                     * @param {string} str String to decode from
 | 
						|
                     * @return {!ProtoBuf.Builder.Message} Decoded message
 | 
						|
                     * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still
 | 
						|
                     *  returns the decoded message with missing fields in the `decoded` property on the error.
 | 
						|
                     * @expose
 | 
						|
                     */
 | 
						|
                    Message.decodeHex = function(str) {
 | 
						|
                        return Message.decode(str, "hex");
 | 
						|
                    };
 | 
						|
        
 | 
						|
                    // Utility
 | 
						|
        
 | 
						|
                    /**
 | 
						|
                     * Returns a string representation of this Message.
 | 
						|
                     * @name ProtoBuf.Builder.Message#toString
 | 
						|
                     * @function
 | 
						|
                     * @return {string} String representation as of ".Fully.Qualified.MessageName"
 | 
						|
                     * @expose
 | 
						|
                     */
 | 
						|
                    Message.prototype.toString = function() {
 | 
						|
                        return T.toString();
 | 
						|
                    };
 | 
						|
        
 | 
						|
                    // Static
 | 
						|
                    
 | 
						|
                    /**
 | 
						|
                     * Options.
 | 
						|
                     * @name ProtoBuf.Builder.Message.$options
 | 
						|
                     * @type {Object.<string,*>}
 | 
						|
                     * @expose
 | 
						|
                     */
 | 
						|
                    var O_o; // for cc
 | 
						|
                    
 | 
						|
                    if (Object.defineProperty) {
 | 
						|
                        Object.defineProperty(Message, '$options', {
 | 
						|
                            'value': T.buildOpt(),
 | 
						|
                            'enumerable': false,
 | 
						|
                            'configurable': false,
 | 
						|
                            'writable': false
 | 
						|
                        });
 | 
						|
                    }
 | 
						|
                    
 | 
						|
                    return Message;
 | 
						|
        
 | 
						|
                })(ProtoBuf, this);
 | 
						|
        
 | 
						|
                // Static enums and prototyped sub-messages
 | 
						|
                var children = this.getChildren();
 | 
						|
                for (var i=0; i<children.length; i++) {
 | 
						|
                    if (children[i] instanceof Enum) {
 | 
						|
                        clazz[children[i]['name']] = children[i].build();
 | 
						|
                    } else if (children[i] instanceof Message) {
 | 
						|
                        clazz[children[i]['name']] = children[i].build();
 | 
						|
                    } else if (children[i] instanceof Message.Field) {
 | 
						|
                        // Ignore
 | 
						|
                    } else {
 | 
						|
                        throw(new Error("Illegal reflect child of "+this.toString(true)+": "+children[i].toString(true)));
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                return this.clazz = clazz;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Encodes a runtime message's contents to the specified buffer.
 | 
						|
             * @param {ProtoBuf.Builder.Message} message Runtime message to encode
 | 
						|
             * @param {ByteBuffer} buffer ByteBuffer to write to
 | 
						|
             * @return {ByteBuffer} The ByteBuffer for chaining
 | 
						|
             * @throws {string} If requried fields are missing or the message cannot be encoded for another reason
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Message.prototype.encode = function(message, buffer) {
 | 
						|
                var fields = this.getChildren(Message.Field),
 | 
						|
                    fieldMissing = null;
 | 
						|
                for (var i=0; i<fields.length; i++) {
 | 
						|
                    var val = message.get(fields[i].name);
 | 
						|
                    if (fields[i].required && val === null) {
 | 
						|
                        if (fieldMissing === null) fieldMissing = fields[i];
 | 
						|
                    } else {
 | 
						|
                        fields[i].encode(val, buffer);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                if (fieldMissing !== null) {
 | 
						|
                    var err = new Error("Missing at least one required field for "+this.toString(true)+": "+fieldMissing);
 | 
						|
                    err["encoded"] = buffer; // Still expose what we got
 | 
						|
                    throw(err);
 | 
						|
                }
 | 
						|
                return buffer;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Decodes an encoded message and returns the decoded message.
 | 
						|
             * @param {ByteBuffer} buffer ByteBuffer to decode from
 | 
						|
             * @param {number=} length Message length. Defaults to decode all the available data.
 | 
						|
             * @return {ProtoBuf.Builder.Message} Decoded message
 | 
						|
             * @throws {Error} If the message cannot be decoded
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Message.prototype.decode = function(buffer, length) {
 | 
						|
                length = typeof length === 'number' ? length : -1;
 | 
						|
                var start = buffer.offset;
 | 
						|
                var msg = new (this.clazz)();
 | 
						|
                while (buffer.offset < start+length || (length == -1 && buffer.remaining() > 0)) {
 | 
						|
                    var tag = buffer.readVarint32();
 | 
						|
                    var wireType = tag & 0x07,
 | 
						|
                        id = tag >> 3;
 | 
						|
                    var field = this.getChild(id); // Message.Field only
 | 
						|
                    if (!field) {
 | 
						|
                        // "messages created by your new code can be parsed by your old code: old binaries simply ignore the new field when parsing."
 | 
						|
                        switch (wireType) {
 | 
						|
                            case ProtoBuf.WIRE_TYPES.VARINT:
 | 
						|
                                buffer.readVarint32();
 | 
						|
                                break;
 | 
						|
                            case ProtoBuf.WIRE_TYPES.BITS32:
 | 
						|
                                buffer.offset += 4;
 | 
						|
                                break;
 | 
						|
                            case ProtoBuf.WIRE_TYPES.BITS64:
 | 
						|
                                buffer.offset += 8;
 | 
						|
                                break;
 | 
						|
                            case ProtoBuf.WIRE_TYPES.LDELIM:
 | 
						|
                                var len = buffer.readVarint32();
 | 
						|
                                buffer.offset += len;
 | 
						|
                                break;
 | 
						|
                            default:
 | 
						|
                                throw(new Error("Illegal wire type of unknown field "+id+" in "+this.toString(true)+"#decode: "+wireType));
 | 
						|
                        }
 | 
						|
                        continue;
 | 
						|
                    }
 | 
						|
                    if (field.repeated && !field.options["packed"]) {
 | 
						|
                        msg.add(field.name, field.decode(wireType, buffer));
 | 
						|
                    } else {
 | 
						|
                        msg.set(field.name, field.decode(wireType, buffer));
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                // Check if all required fields are present
 | 
						|
                var fields = this.getChildren(ProtoBuf.Reflect.Field);
 | 
						|
                for (var i=0; i<fields.length; i++) {
 | 
						|
                    if (fields[i].required && msg[fields[i].name] === null) {
 | 
						|
                        var err = new Error("Missing at least one required field for "+this.toString(true)+": "+fields[i].name);
 | 
						|
                        err["decoded"] = msg; // Still expose what we got
 | 
						|
                        throw(err);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                return msg;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * @alias ProtoBuf.Reflect.Message
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Reflect.Message = Message;
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Constructs a new Message Field.
 | 
						|
             * @exports ProtoBuf.Reflect.Message.Field
 | 
						|
             * @param {ProtoBuf.Reflect.Message} message Message reference
 | 
						|
             * @param {string} rule Rule, one of requried, optional, repeated
 | 
						|
             * @param {string} type Data type, e.g. int32
 | 
						|
             * @param {string} name Field name
 | 
						|
             * @param {number} id Unique field id
 | 
						|
             * @param {Object.<string.*>=} options Options
 | 
						|
             * @constructor
 | 
						|
             * @extends ProtoBuf.Reflect.T
 | 
						|
             */
 | 
						|
            var Field = function(message, rule, type, name, id, options) {
 | 
						|
                T.call(this, message, name);
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Message field required flag.
 | 
						|
                 * @type {boolean}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.required = rule == "required";
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Message field repeated flag.
 | 
						|
                 * @type {boolean}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.repeated = rule == "repeated";
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Message field type. Type reference string if unresolved, protobuf type if resolved.
 | 
						|
                 * @type {string|{name: string, wireType: number}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.type = type;
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Resolved type reference inside the global namespace.
 | 
						|
                 * @type {ProtoBuf.Reflect.T|null}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.resolvedType = null;
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Unique message field id.
 | 
						|
                 * @type {number}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.id = id;
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Message field options.
 | 
						|
                 * @type {!Object.<string,*>}
 | 
						|
                 * @dict
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.options = options || {};
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Original field name.
 | 
						|
                 * @type {string}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.originalName = this.name; // Used to revert camelcase transformation on naming collisions
 | 
						|
                
 | 
						|
                // Convert field names to camel case notation if the override is set
 | 
						|
                if (ProtoBuf.convertFieldsToCamelCase) {
 | 
						|
                    this.name = this.name.replace(/_([a-zA-Z])/g, function($0, $1) {
 | 
						|
                        return $1.toUpperCase();
 | 
						|
                    });
 | 
						|
                }
 | 
						|
            };
 | 
						|
        
 | 
						|
            // Extends T
 | 
						|
            Field.prototype = Object.create(T.prototype);
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Checks if the given value can be set for this field.
 | 
						|
             * @param {*} value Value to check
 | 
						|
             * @param {boolean=} skipRepeated Whether to skip the repeated value check or not. Defaults to false.
 | 
						|
             * @return {*} Verified, maybe adjusted, value
 | 
						|
             * @throws {Error} If the value cannot be set for this field
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Field.prototype.verifyValue = function(value, skipRepeated) {
 | 
						|
                skipRepeated = skipRepeated || false;
 | 
						|
                if (value === null) { // NULL values for optional fields
 | 
						|
                    if (this.required) {
 | 
						|
                        throw(new Error("Illegal value for "+this.toString(true)+": "+value+" (required)"));
 | 
						|
                    }
 | 
						|
                    return null;
 | 
						|
                }
 | 
						|
                var i;
 | 
						|
                if (this.repeated && !skipRepeated) { // Repeated values as arrays
 | 
						|
                    if (!ProtoBuf.Util.isArray(value)) {
 | 
						|
                        value = [value];
 | 
						|
                    }
 | 
						|
                    var res = [];
 | 
						|
                    for (i=0; i<value.length; i++) {
 | 
						|
                        res.push(this.verifyValue(value[i], true));
 | 
						|
                    }
 | 
						|
                    return res;
 | 
						|
                }
 | 
						|
                // All non-repeated fields expect no array
 | 
						|
                if (!this.repeated && ProtoBuf.Util.isArray(value)) {
 | 
						|
                    throw(new Error("Illegal value for "+this.toString(true)+": "+value+" (no array expected)"));
 | 
						|
                }
 | 
						|
                // Signed 32bit
 | 
						|
                if (this.type == ProtoBuf.TYPES["int32"] || this.type == ProtoBuf.TYPES["sint32"] || this.type == ProtoBuf.TYPES["sfixed32"]) {
 | 
						|
                    return isNaN(i = parseInt(value, 10)) ? i : i | 0; // Do not cast NaN as it'd become 0
 | 
						|
                }
 | 
						|
                // Unsigned 32bit
 | 
						|
                if (this.type == ProtoBuf.TYPES["uint32"] || this.type == ProtoBuf.TYPES["fixed32"]) {
 | 
						|
                    return isNaN(i = parseInt(value, 10)) ? i : i >>> 0; // Do not cast NaN as it'd become 0
 | 
						|
                }
 | 
						|
                if (ProtoBuf.Long) {
 | 
						|
                    // Signed 64bit
 | 
						|
                    if (this.type == ProtoBuf.TYPES["int64"] || this.type == ProtoBuf.TYPES["sint64"] || this.type == ProtoBuf.TYPES["sfixed64"]) {
 | 
						|
                        if (!(typeof value == 'object' && value instanceof ProtoBuf.Long)) {
 | 
						|
                            return ProtoBuf.Long.fromNumber(value, false);
 | 
						|
                        }
 | 
						|
                        return value.unsigned ? value.toSigned() : value;
 | 
						|
                    }
 | 
						|
                    // Unsigned 64bit
 | 
						|
                    if (this.type == ProtoBuf.TYPES["uint64"] || this.type == ProtoBuf.TYPES["fixed64"]) {
 | 
						|
                        if (!(typeof value == 'object' && value instanceof ProtoBuf.Long)) {
 | 
						|
                            return ProtoBuf.Long.fromNumber(value, true);
 | 
						|
                        }
 | 
						|
                        return value.unsigned ? value : value.toUnsigned();
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                // Bool
 | 
						|
                if (this.type == ProtoBuf.TYPES["bool"]) {
 | 
						|
                    if (typeof value === 'string') return value === 'true';
 | 
						|
                    else return !!value;
 | 
						|
                }
 | 
						|
                // Float
 | 
						|
                if (this.type == ProtoBuf.TYPES["float"] || this.type == ProtoBuf.TYPES["double"]) {
 | 
						|
                    return parseFloat(value); // May also become NaN, +Infinity, -Infinity
 | 
						|
                }
 | 
						|
                // Length-delimited string
 | 
						|
                if (this.type == ProtoBuf.TYPES["string"]) {
 | 
						|
                    return ""+value;
 | 
						|
                }
 | 
						|
                // Length-delimited bytes
 | 
						|
                if (this.type == ProtoBuf.TYPES["bytes"]) {
 | 
						|
                    if (value && value instanceof ByteBuffer) {
 | 
						|
                        return value;
 | 
						|
                    }
 | 
						|
                    return ByteBuffer.wrap(value);
 | 
						|
                }
 | 
						|
                // Constant enum value
 | 
						|
                if (this.type == ProtoBuf.TYPES["enum"]) {
 | 
						|
                    var values = this.resolvedType.getChildren(Enum.Value);
 | 
						|
                    for (i=0; i<values.length; i++) {
 | 
						|
                        if (values[i].name == value) {
 | 
						|
                            return values[i].id;
 | 
						|
                        } else if (values[i].id == value) {
 | 
						|
                            return values[i].id;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    throw(new Error("Illegal value for "+this.toString(true)+": "+value+" (not a valid enum value)"));
 | 
						|
                }
 | 
						|
                // Embedded message
 | 
						|
                if (this.type == ProtoBuf.TYPES["message"]) {
 | 
						|
                    if (typeof value !== 'object') {
 | 
						|
                        throw(new Error("Illegal value for "+this.toString(true)+": "+value+" (object expected)"));
 | 
						|
                    }
 | 
						|
                    if (value instanceof this.resolvedType.clazz) {
 | 
						|
                        return value;
 | 
						|
                    }
 | 
						|
                    // Else let's try to construct one from a key-value object
 | 
						|
                    return new (this.resolvedType.clazz)(value); // May throw for a hundred of reasons
 | 
						|
                }
 | 
						|
                // We should never end here
 | 
						|
                throw(new Error("[INTERNAL] Illegal value for "+this.toString(true)+": "+value+" (undefined type "+this.type+")"));
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Encodes the specified field value to the specified buffer.
 | 
						|
             * @param {*} value Field value
 | 
						|
             * @param {ByteBuffer} buffer ByteBuffer to encode to
 | 
						|
             * @return {ByteBuffer} The ByteBuffer for chaining
 | 
						|
             * @throws {Error} If the field cannot be encoded
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Field.prototype.encode = function(value, buffer) {
 | 
						|
                value = this.verifyValue(value); // May throw
 | 
						|
                if (this.type == null || typeof this.type != 'object') {
 | 
						|
                    throw(new Error("[INTERNAL] Unresolved type in "+this.toString(true)+": "+this.type));
 | 
						|
                }
 | 
						|
                if (value === null || (this.repeated && value.length == 0)) return buffer; // Optional omitted
 | 
						|
                try {
 | 
						|
                    if (this.repeated) {
 | 
						|
                        var i;
 | 
						|
                        if (this.options["packed"]) {
 | 
						|
                            // "All of the elements of the field are packed into a single key-value pair with wire type 2
 | 
						|
                            // (length-delimited). Each element is encoded the same way it would be normally, except without a
 | 
						|
                            // tag preceding it." 
 | 
						|
                            buffer.writeVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM);
 | 
						|
                            buffer.ensureCapacity(buffer.offset += 1); // We do not know the length yet, so let's assume a varint of length 1
 | 
						|
                            var start = buffer.offset; // Remember where the contents begin
 | 
						|
                            for (i=0; i<value.length; i++) {
 | 
						|
                                this.encodeValue(value[i], buffer);
 | 
						|
                            }
 | 
						|
                            var len = buffer.offset-start;
 | 
						|
                            var varintLen = ByteBuffer.calculateVarint32(len);
 | 
						|
                            if (varintLen > 1) { // We need to move the contents
 | 
						|
                                var contents = buffer.slice(start, buffer.offset);
 | 
						|
                                start += varintLen-1;
 | 
						|
                                buffer.offset = start;
 | 
						|
                                buffer.append(contents);
 | 
						|
                            }
 | 
						|
                            buffer.writeVarint32(len, start-varintLen);
 | 
						|
                        } else {
 | 
						|
                            // "If your message definition has repeated elements (without the [packed=true] option), the encoded
 | 
						|
                            // message has zero or more key-value pairs with the same tag number"
 | 
						|
                            for (i=0; i<value.length; i++) {
 | 
						|
                                buffer.writeVarint32((this.id << 3) | this.type.wireType);
 | 
						|
                                this.encodeValue(value[i], buffer);
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    } else {
 | 
						|
                        buffer.writeVarint32((this.id << 3) | this.type.wireType);
 | 
						|
                        this.encodeValue(value, buffer);
 | 
						|
                    }
 | 
						|
                } catch (e) {
 | 
						|
                    throw(new Error("Illegal value for "+this.toString(true)+": "+value+" ("+e+")"));
 | 
						|
                }
 | 
						|
                return buffer;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Encodes a value to the specified buffer. Does not encode the key.
 | 
						|
             * @param {*} value Field value
 | 
						|
             * @param {ByteBuffer} buffer ByteBuffer to encode to
 | 
						|
             * @return {ByteBuffer} The ByteBuffer for chaining
 | 
						|
             * @throws {Error} If the value cannot be encoded
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Field.prototype.encodeValue = function(value, buffer) {
 | 
						|
                if (value === null) return; // Nothing to encode
 | 
						|
                // Tag has already been written
 | 
						|
        
 | 
						|
                // 32bit varint as-is
 | 
						|
                if (this.type == ProtoBuf.TYPES["int32"] || this.type == ProtoBuf.TYPES["uint32"]) {
 | 
						|
                    buffer.writeVarint32(value);
 | 
						|
                    
 | 
						|
                // 32bit varint zig-zag
 | 
						|
                } else if (this.type == ProtoBuf.TYPES["sint32"]) {
 | 
						|
                    buffer.writeZigZagVarint32(value);
 | 
						|
                    
 | 
						|
                // Fixed unsigned 32bit
 | 
						|
                } else if (this.type == ProtoBuf.TYPES["fixed32"]) {
 | 
						|
                    buffer.writeUint32(value);
 | 
						|
                    
 | 
						|
                // Fixed signed 32bit
 | 
						|
                } else if (this.type == ProtoBuf.TYPES["sfixed32"]) {
 | 
						|
                    buffer.writeInt32(value);
 | 
						|
                
 | 
						|
                // 64bit varint as-is
 | 
						|
                } else if (this.type == ProtoBuf.TYPES["int64"] || this.type == ProtoBuf.TYPES["uint64"]) {
 | 
						|
                    buffer.writeVarint64(value); // throws
 | 
						|
                    
 | 
						|
                // 64bit varint zig-zag
 | 
						|
                } else if (this.type == ProtoBuf.TYPES["sint64"]) {
 | 
						|
                    buffer.writeZigZagVarint64(value); // throws
 | 
						|
                    
 | 
						|
                // Fixed unsigned 64bit
 | 
						|
                } else if (this.type == ProtoBuf.TYPES["fixed64"]) {
 | 
						|
                    buffer.writeUint64(value); // throws
 | 
						|
                    
 | 
						|
                // Fixed signed 64bit
 | 
						|
                } else if (this.type == ProtoBuf.TYPES["sfixed64"]) {
 | 
						|
                    buffer.writeInt64(value); // throws
 | 
						|
                    
 | 
						|
                // Bool
 | 
						|
                } else if (this.type == ProtoBuf.TYPES["bool"]) {
 | 
						|
                    if (typeof value === 'string') buffer.writeVarint32(value.toLowerCase() === 'false' ? 0 : !!value);
 | 
						|
                    else buffer.writeVarint32(value ? 1 : 0);
 | 
						|
                    
 | 
						|
                // Constant enum value
 | 
						|
                } else if (this.type == ProtoBuf.TYPES["enum"]) {
 | 
						|
                    buffer.writeVarint32(value);
 | 
						|
                    
 | 
						|
                // 32bit float
 | 
						|
                } else if (this.type == ProtoBuf.TYPES["float"]) {
 | 
						|
                    buffer.writeFloat32(value);
 | 
						|
                    
 | 
						|
                // 64bit float
 | 
						|
                } else if (this.type == ProtoBuf.TYPES["double"]) {
 | 
						|
                    buffer.writeFloat64(value);
 | 
						|
                    
 | 
						|
                // Length-delimited string
 | 
						|
                } else if (this.type == ProtoBuf.TYPES["string"]) {
 | 
						|
                    buffer.writeVString(value);
 | 
						|
                    
 | 
						|
                // Length-delimited bytes
 | 
						|
                } else if (this.type == ProtoBuf.TYPES["bytes"]) {
 | 
						|
                    if (value.offset > value.length) { // Forgot to flip?
 | 
						|
                        buffer = buffer.clone().flip();
 | 
						|
                    }
 | 
						|
                    buffer.writeVarint32(value.remaining());
 | 
						|
                    buffer.append(value);
 | 
						|
                    
 | 
						|
                // Embedded message
 | 
						|
                } else if (this.type == ProtoBuf.TYPES["message"]) {
 | 
						|
                    var bb = new ByteBuffer().LE();
 | 
						|
                    this.resolvedType.encode(value, bb);
 | 
						|
                    buffer.writeVarint32(bb.offset);
 | 
						|
                    buffer.append(bb.flip());
 | 
						|
                } else {
 | 
						|
                    // We should never end here
 | 
						|
                    throw(new Error("[INTERNAL] Illegal value to encode in "+this.toString(true)+": "+value+" (unknown type)"));
 | 
						|
                }
 | 
						|
                return buffer;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Decode the field value from the specified buffer.
 | 
						|
             * @param {number} wireType Leading wire type
 | 
						|
             * @param {ByteBuffer} buffer ByteBuffer to decode from
 | 
						|
             * @param {boolean=} skipRepeated Whether to skip the repeated check or not. Defaults to false.
 | 
						|
             * @return {*} Decoded value
 | 
						|
             * @throws {Error} If the field cannot be decoded
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Field.prototype.decode = function(wireType, buffer, skipRepeated) {
 | 
						|
                var value, nBytes;
 | 
						|
                if (wireType != this.type.wireType && (skipRepeated || (wireType != ProtoBuf.WIRE_TYPES.LDELIM || !this.repeated))) {
 | 
						|
                    throw(new Error("Illegal wire type for field "+this.toString(true)+": "+wireType+" ("+this.type.wireType+" expected)"));
 | 
						|
                }
 | 
						|
                if (wireType == ProtoBuf.WIRE_TYPES.LDELIM && this.repeated && this.options["packed"]) {
 | 
						|
                    if (!skipRepeated) {
 | 
						|
                        nBytes = buffer.readVarint32();
 | 
						|
                        nBytes = buffer.offset + nBytes; // Limit
 | 
						|
                        var values = [];
 | 
						|
                        while (buffer.offset < nBytes) {
 | 
						|
                            values.push(this.decode(this.type.wireType, buffer, true));
 | 
						|
                        }
 | 
						|
                        return values;
 | 
						|
                    }
 | 
						|
                    // Read the next value otherwise...
 | 
						|
                    
 | 
						|
                }
 | 
						|
                // 32bit signed varint
 | 
						|
                if (this.type == ProtoBuf.TYPES["int32"]) {
 | 
						|
                    return buffer.readVarint32() | 0;
 | 
						|
                }
 | 
						|
                
 | 
						|
                // 32bit unsigned varint
 | 
						|
                if (this.type == ProtoBuf.TYPES["uint32"]) {
 | 
						|
                    return buffer.readVarint32() >>> 0;
 | 
						|
                }
 | 
						|
                
 | 
						|
                // 32bit signed varint zig-zag
 | 
						|
                if (this.type == ProtoBuf.TYPES["sint32"]) {
 | 
						|
                    return buffer.readZigZagVarint32() | 0;
 | 
						|
                }
 | 
						|
                
 | 
						|
                // Fixed 32bit unsigned
 | 
						|
                if (this.type == ProtoBuf.TYPES["fixed32"]) {
 | 
						|
                    return buffer.readUint32() >>> 0;
 | 
						|
                }
 | 
						|
                
 | 
						|
                // Fixed 32bit signed
 | 
						|
                if (this.type == ProtoBuf.TYPES["sfixed32"]) {
 | 
						|
                    return buffer.readInt32() | 0;
 | 
						|
                }
 | 
						|
                
 | 
						|
                // 64bit signed varint
 | 
						|
                if (this.type == ProtoBuf.TYPES["int64"]) {
 | 
						|
                    return buffer.readVarint64();
 | 
						|
                }
 | 
						|
                
 | 
						|
                // 64bit unsigned varint
 | 
						|
                if (this.type == ProtoBuf.TYPES["uint64"]) {
 | 
						|
                    return buffer.readVarint64().toUnsigned();
 | 
						|
                }
 | 
						|
                
 | 
						|
                // 64bit signed varint zig-zag
 | 
						|
                if (this.type == ProtoBuf.TYPES["sint64"]) {
 | 
						|
                    return buffer.readZigZagVarint64();
 | 
						|
                }
 | 
						|
        
 | 
						|
                // Fixed 64bit unsigned
 | 
						|
                if (this.type == ProtoBuf.TYPES["fixed64"]) {
 | 
						|
                    return buffer.readUint64();
 | 
						|
                }
 | 
						|
                
 | 
						|
                // Fixed 64bit signed
 | 
						|
                if (this.type == ProtoBuf.TYPES["sfixed64"]) {
 | 
						|
                    return buffer.readInt64();
 | 
						|
                }
 | 
						|
                
 | 
						|
                // Bool varint
 | 
						|
                if (this.type == ProtoBuf.TYPES["bool"]) {
 | 
						|
                    return !!buffer.readVarint32();
 | 
						|
                }
 | 
						|
                
 | 
						|
                // Constant enum value varint)
 | 
						|
                if (this.type == ProtoBuf.TYPES["enum"]) {
 | 
						|
                    return buffer.readVarint32(); // The following Builder.Message#set will already throw
 | 
						|
                }
 | 
						|
                
 | 
						|
                // 32bit float
 | 
						|
                if (this.type == ProtoBuf.TYPES["float"]) {
 | 
						|
                    return buffer.readFloat();
 | 
						|
                }
 | 
						|
                // 64bit float
 | 
						|
                if (this.type == ProtoBuf.TYPES["double"]) {
 | 
						|
                    return buffer.readDouble();
 | 
						|
                }
 | 
						|
                
 | 
						|
                // Length-delimited string
 | 
						|
                if (this.type == ProtoBuf.TYPES["string"]){
 | 
						|
                    return buffer.readVString();
 | 
						|
                }
 | 
						|
                
 | 
						|
                // Length-delimited bytes
 | 
						|
                if (this.type == ProtoBuf.TYPES["bytes"]) {
 | 
						|
                    nBytes = buffer.readVarint32();
 | 
						|
                    if (buffer.remaining() < nBytes) {
 | 
						|
                        throw(new Error("Illegal number of bytes for "+this.toString(true)+": "+nBytes+" required but got only "+buffer.remaining()));
 | 
						|
                    }
 | 
						|
                    value = buffer.clone(); // Offset already set
 | 
						|
                    value.length = value.offset+nBytes;
 | 
						|
                    buffer.offset += nBytes;
 | 
						|
                    return value;
 | 
						|
                }
 | 
						|
                
 | 
						|
                // Length-delimited embedded message
 | 
						|
                if (this.type == ProtoBuf.TYPES["message"]) {
 | 
						|
                    nBytes = buffer.readVarint32();
 | 
						|
                    return this.resolvedType.decode(buffer, nBytes);
 | 
						|
                }
 | 
						|
                
 | 
						|
                // We should never end here
 | 
						|
                throw(new Error("[INTERNAL] Illegal wire type for "+this.toString(true)+": "+wireType));
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * @alias ProtoBuf.Reflect.Message.Field
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Reflect.Message.Field = Field;
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Constructs a new Enum.
 | 
						|
             * @exports ProtoBuf.Reflect.Enum
 | 
						|
             * @param {!ProtoBuf.Reflect.T} parent Parent Reflect object
 | 
						|
             * @param {string} name Enum name
 | 
						|
             * @param {Object.<string.*>=} options Enum options
 | 
						|
             * @constructor
 | 
						|
             * @extends ProtoBuf.Reflect.Namespace
 | 
						|
             */
 | 
						|
            var Enum = function(parent, name, options) {
 | 
						|
                Namespace.call(this, parent, name, options);
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Runtime enum object.
 | 
						|
                 * @type {Object.<string,number>|null}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.object = null;
 | 
						|
            };
 | 
						|
        
 | 
						|
            // Extends Namespace
 | 
						|
            Enum.prototype = Object.create(Namespace.prototype);
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Builds this enum and returns the runtime counterpart.
 | 
						|
             * @return {Object<string,*>}
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Enum.prototype.build = function() {
 | 
						|
                var enm = {};
 | 
						|
                var values = this.getChildren(Enum.Value);
 | 
						|
                for (var i=0; i<values.length; i++) {
 | 
						|
                    enm[values[i]['name']] = values[i]['id'];
 | 
						|
                }
 | 
						|
                if (Object.defineProperty) {
 | 
						|
                    Object.defineProperty(enm, '$options', {
 | 
						|
                        'value': this.buildOpt(),
 | 
						|
                        'enumerable': false,
 | 
						|
                        'configurable': false,
 | 
						|
                        'writable': false
 | 
						|
                    });
 | 
						|
                }
 | 
						|
                return this.object = enm;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * @alias ProtoBuf.Reflect.Enum
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Reflect.Enum = Enum;
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Constructs a new Enum Value.
 | 
						|
             * @exports ProtoBuf.Reflect.Enum.Value
 | 
						|
             * @param {!ProtoBuf.Reflect.Enum} enm Enum reference
 | 
						|
             * @param {string} name Field name
 | 
						|
             * @param {number} id Unique field id
 | 
						|
             * @constructor
 | 
						|
             * @extends ProtoBuf.Reflect.T
 | 
						|
             */
 | 
						|
            var Value = function(enm, name, id) {
 | 
						|
                T.call(this, enm, name);
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Unique enum value id.
 | 
						|
                 * @type {number}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.id = id;
 | 
						|
            };
 | 
						|
        
 | 
						|
            // Extends T
 | 
						|
            Value.prototype = Object.create(T.prototype);
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * @alias ProtoBuf.Reflect.Enum.Value
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Reflect.Enum.Value = Value;
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Constructs a new Service.
 | 
						|
             * @exports ProtoBuf.Reflect.Service
 | 
						|
             * @param {!ProtoBuf.Reflect.Namespace} root Root
 | 
						|
             * @param {string} name Service name
 | 
						|
             * @param {Object.<string,*>=} options Options
 | 
						|
             * @constructor
 | 
						|
             * @extends ProtoBuf.Reflect.Namespace
 | 
						|
             */
 | 
						|
            var Service = function(root, name, options) {
 | 
						|
                Namespace.call(this, root, name, options);
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Built runtime service class.
 | 
						|
                 * @type {?function(new:ProtoBuf.Builder.Service)}
 | 
						|
                 */
 | 
						|
                this.clazz = null;
 | 
						|
            };
 | 
						|
            
 | 
						|
            // Extends Namespace
 | 
						|
            Service.prototype = Object.create(Namespace.prototype);
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Builds the service and returns the runtime counterpart, which is a fully functional class.
 | 
						|
             * @see ProtoBuf.Builder.Service
 | 
						|
             * @param {boolean=} rebuild Whether to rebuild or not
 | 
						|
             * @return {Function} Service class
 | 
						|
             * @throws {Error} If the message cannot be built
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Service.prototype.build = function(rebuild) {
 | 
						|
                if (this.clazz && !rebuild) return this.clazz;
 | 
						|
                return this.clazz = (function(ProtoBuf, T) {
 | 
						|
        
 | 
						|
                    /**
 | 
						|
                     * Constructs a new runtime Service.
 | 
						|
                     * @name ProtoBuf.Builder.Service
 | 
						|
                     * @param {function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))=} rpcImpl RPC implementation receiving the method name and the message
 | 
						|
                     * @class Barebone of all runtime services.
 | 
						|
                     * @constructor
 | 
						|
                     * @throws {Error} If the service cannot be created
 | 
						|
                     */
 | 
						|
                    var Service = function(rpcImpl) {
 | 
						|
                        ProtoBuf.Builder.Service.call(this);
 | 
						|
        
 | 
						|
                        /**
 | 
						|
                         * Service implementation.
 | 
						|
                         * @name ProtoBuf.Builder.Service#rpcImpl
 | 
						|
                         * @type {!function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))}
 | 
						|
                         * @expose
 | 
						|
                         */
 | 
						|
                        this.rpcImpl = rpcImpl || function(name, msg, callback) {
 | 
						|
                            // This is what a user has to implement: A function receiving the method name, the actual message to
 | 
						|
                            // send (type checked) and the callback that's either provided with the error as its first
 | 
						|
                            // argument or null and the actual response message.
 | 
						|
                            setTimeout(callback.bind(this, new Error("Not implemented, see: https://github.com/dcodeIO/ProtoBuf.js/wiki/Services")), 0); // Must be async!
 | 
						|
                        };
 | 
						|
                    };
 | 
						|
                    
 | 
						|
                    // Extends ProtoBuf.Builder.Service
 | 
						|
                    Service.prototype = Object.create(ProtoBuf.Builder.Service.prototype);
 | 
						|
                    
 | 
						|
                    if (Object.defineProperty) {
 | 
						|
                        Object.defineProperty(Service, "$options", {
 | 
						|
                            "value": T.buildOpt(),
 | 
						|
                            "enumerable": false,
 | 
						|
                            "configurable": false,
 | 
						|
                            "writable": false
 | 
						|
                        });
 | 
						|
                        Object.defineProperty(Service.prototype, "$options", {
 | 
						|
                            "value": Service["$options"],
 | 
						|
                            "enumerable": false,
 | 
						|
                            "configurable": false,
 | 
						|
                            "writable": false
 | 
						|
                        });
 | 
						|
                    }
 | 
						|
        
 | 
						|
                    /**
 | 
						|
                     * Asynchronously performs an RPC call using the given RPC implementation.
 | 
						|
                     * @name ProtoBuf.Builder.Service.[Method]
 | 
						|
                     * @function
 | 
						|
                     * @param {!function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))} rpcImpl RPC implementation
 | 
						|
                     * @param {ProtoBuf.Builder.Message} req Request
 | 
						|
                     * @param {function(Error, (ProtoBuf.Builder.Message|ByteBuffer|Buffer|string)=)} callback Callback receiving
 | 
						|
                     *  the error if any and the response either as a pre-parsed message or as its raw bytes
 | 
						|
                     * @abstract
 | 
						|
                     */
 | 
						|
        
 | 
						|
                    /**
 | 
						|
                     * Asynchronously performs an RPC call using the instance's RPC implementation.
 | 
						|
                     * @name ProtoBuf.Builder.Service#[Method]
 | 
						|
                     * @function
 | 
						|
                     * @param {ProtoBuf.Builder.Message} req Request
 | 
						|
                     * @param {function(Error, (ProtoBuf.Builder.Message|ByteBuffer|Buffer|string)=)} callback Callback receiving
 | 
						|
                     *  the error if any and the response either as a pre-parsed message or as its raw bytes
 | 
						|
                     * @abstract
 | 
						|
                     */
 | 
						|
                    
 | 
						|
                    var rpc = T.getChildren(Reflect.Service.RPCMethod);
 | 
						|
                    for (var i=0; i<rpc.length; i++) {
 | 
						|
                        (function(method) {
 | 
						|
                            
 | 
						|
                            // service#Method(message, callback)
 | 
						|
                            Service.prototype[method.name] = function(req, callback) {
 | 
						|
                                try {
 | 
						|
                                    if (!req || !(req instanceof method.resolvedRequestType.clazz)) {
 | 
						|
                                        setTimeout(callback.bind(this, new Error("Illegal request type provided to service method "+T.name+"#"+method.name)));
 | 
						|
                                    }
 | 
						|
                                    this.rpcImpl(method.fqn(), req, function(err, res) { // Assumes that this is properly async
 | 
						|
                                        if (err) {
 | 
						|
                                            callback(err);
 | 
						|
                                            return;
 | 
						|
                                        }
 | 
						|
                                        try { res = method.resolvedResponseType.clazz.decode(res); } catch (notABuffer) {}
 | 
						|
                                        if (!res || !(res instanceof method.resolvedResponseType.clazz)) {
 | 
						|
                                            callback(new Error("Illegal response type received in service method "+ T.name+"#"+method.name));
 | 
						|
                                            return;
 | 
						|
                                        }
 | 
						|
                                        callback(null, res);
 | 
						|
                                    });
 | 
						|
                                } catch (err) {
 | 
						|
                                    setTimeout(callback.bind(this, err), 0);
 | 
						|
                                }
 | 
						|
                            };
 | 
						|
        
 | 
						|
                            // Service.Method(rpcImpl, message, callback)
 | 
						|
                            Service[method.name] = function(rpcImpl, req, callback) {
 | 
						|
                                new Service(rpcImpl)[method.name](req, callback);
 | 
						|
                            };
 | 
						|
        
 | 
						|
                            if (Object.defineProperty) {
 | 
						|
                                Object.defineProperty(Service[method.name], "$options", {
 | 
						|
                                    "value": method.buildOpt(),
 | 
						|
                                    "enumerable": false,
 | 
						|
                                    "configurable": false,
 | 
						|
                                    "writable": false
 | 
						|
                                });
 | 
						|
                                Object.defineProperty(Service.prototype[method.name], "$options", {
 | 
						|
                                    "value": Service[method.name]["$options"],
 | 
						|
                                    "enumerable": false,
 | 
						|
                                    "configurable": false,
 | 
						|
                                    "writable": false
 | 
						|
                                });
 | 
						|
                            }
 | 
						|
                        })(rpc[i]);
 | 
						|
                    }
 | 
						|
                    
 | 
						|
                    return Service;
 | 
						|
                    
 | 
						|
                })(ProtoBuf, this);
 | 
						|
            };
 | 
						|
            
 | 
						|
            Reflect.Service = Service;
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Abstract service method.
 | 
						|
             * @exports ProtoBuf.Reflect.Service.Method
 | 
						|
             * @param {!ProtoBuf.Reflect.Service} svc Service
 | 
						|
             * @param {string} name Method name
 | 
						|
             * @param {Object.<string,*>=} options Options
 | 
						|
             * @constructor
 | 
						|
             * @extends ProtoBuf.Reflect.T
 | 
						|
             */
 | 
						|
            var Method = function(svc, name, options) {
 | 
						|
                T.call(this, svc, name);
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Options.
 | 
						|
                 * @type {Object.<string, *>}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.options = options || {};
 | 
						|
            };
 | 
						|
            
 | 
						|
            // Extends T
 | 
						|
            Method.prototype = Object.create(T.prototype);
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Builds the method's '$options' property.
 | 
						|
             * @name ProtoBuf.Reflect.Service.Method#buildOpt
 | 
						|
             * @function
 | 
						|
             * @return {Object.<string,*>}
 | 
						|
             */
 | 
						|
            Method.prototype.buildOpt = Namespace.prototype.buildOpt;
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * @alias ProtoBuf.Reflect.Service.Method
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Reflect.Service.Method = Method;
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * RPC service method.
 | 
						|
             * @exports ProtoBuf.Reflect.Service.RPCMethod
 | 
						|
             * @param {!ProtoBuf.Reflect.Service} svc Service
 | 
						|
             * @param {string} name Method name
 | 
						|
             * @param {string} request Request message name
 | 
						|
             * @param {string} response Response message name
 | 
						|
             * @param {Object.<string,*>=} options Options
 | 
						|
             * @constructor
 | 
						|
             * @extends ProtoBuf.Reflect.Service.Method
 | 
						|
             */
 | 
						|
            var RPCMethod = function(svc, name, request, response, options) {
 | 
						|
                Method.call(this, svc, name, options);
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Request message name.
 | 
						|
                 * @type {string}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.requestName = request;
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Response message name.
 | 
						|
                 * @type {string}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.responseName = response;
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Resolved request message type.
 | 
						|
                 * @type {ProtoBuf.Reflect.Message}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.resolvedRequestType = null;
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Resolved response message type.
 | 
						|
                 * @type {ProtoBuf.Reflect.Message}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.resolvedResponseType = null;
 | 
						|
            };
 | 
						|
            
 | 
						|
            // Extends Method
 | 
						|
            RPCMethod.prototype = Object.create(Method.prototype);
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * @alias ProtoBuf.Reflect.Service.RPCMethod
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Reflect.Service.RPCMethod = RPCMethod;
 | 
						|
            
 | 
						|
            return Reflect;
 | 
						|
        })(ProtoBuf);
 | 
						|
                
 | 
						|
        /**
 | 
						|
         * @alias ProtoBuf.Builder
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.Builder = (function(ProtoBuf, Lang, Reflect) {
 | 
						|
            "use strict";
 | 
						|
            
 | 
						|
            /**
 | 
						|
             * Constructs a new Builder.
 | 
						|
             * @exports ProtoBuf.Builder
 | 
						|
             * @class Provides the functionality to build protocol messages.
 | 
						|
             * @constructor
 | 
						|
             */
 | 
						|
            var Builder = function() {
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Namespace.
 | 
						|
                 * @type {ProtoBuf.Reflect.Namespace}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.ns = new Reflect.Namespace(null, ""); // Global namespace
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Namespace pointer.
 | 
						|
                 * @type {ProtoBuf.Reflect.T}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.ptr = this.ns;
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Resolved flag.
 | 
						|
                 * @type {boolean}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.resolved = false;
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * The current building result.
 | 
						|
                 * @type {Object.<string,ProtoBuf.Builder.Message|Object>|null}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.result = null;
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Imported files.
 | 
						|
                 * @type {Array.<string>}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.files = {};
 | 
						|
        
 | 
						|
                /**
 | 
						|
                 * Import root override.
 | 
						|
                 * @type {?string}
 | 
						|
                 * @expose
 | 
						|
                 */
 | 
						|
                this.importRoot = null;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Resets the pointer to the global namespace.
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Builder.prototype.reset = function() {
 | 
						|
                this.ptr = this.ns;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Defines a package on top of the current pointer position and places the pointer on it.
 | 
						|
             * @param {string} pkg
 | 
						|
             * @param {Object.<string,*>=} options
 | 
						|
             * @return {ProtoBuf.Builder} this
 | 
						|
             * @throws {Error} If the package name is invalid
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Builder.prototype.define = function(pkg, options) {
 | 
						|
                if (typeof pkg !== 'string' || !Lang.TYPEREF.test(pkg)) {
 | 
						|
                    throw(new Error("Illegal package name: "+pkg));
 | 
						|
                }
 | 
						|
                var part = pkg.split("."), i;
 | 
						|
                for (i=0; i<part.length; i++) { // To be absolutely sure
 | 
						|
                    if (!Lang.NAME.test(part[i])) {
 | 
						|
                        throw(new Error("Illegal package name: "+part[i]));
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                for (i=0; i<part.length; i++) {
 | 
						|
                    if (!this.ptr.hasChild(part[i])) { // Keep existing namespace
 | 
						|
                        this.ptr.addChild(new Reflect.Namespace(this.ptr, part[i], options));
 | 
						|
                    }
 | 
						|
                    this.ptr = this.ptr.getChild(part[i]);
 | 
						|
                }
 | 
						|
                return this;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Tests if a definition is a valid message definition.
 | 
						|
             * @param {Object.<string,*>} def Definition
 | 
						|
             * @return {boolean} true if valid, else false
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Builder.isValidMessage = function(def) {
 | 
						|
                // Messages require a string name
 | 
						|
                if (typeof def["name"] !== 'string' || !Lang.NAME.test(def["name"])) {
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
                // Messages must not contain values (that'd be an enum) or methods (that'd be a service)
 | 
						|
                if (typeof def["values"] !== 'undefined' || typeof def["rpc"] !== 'undefined') {
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
                // Fields, enums and messages are arrays if provided
 | 
						|
                var i;
 | 
						|
                if (typeof def["fields"] !== 'undefined') {
 | 
						|
                    if (!ProtoBuf.Util.isArray(def["fields"])) {
 | 
						|
                        return false;
 | 
						|
                    }
 | 
						|
                    var ids = [], id; // IDs must be unique
 | 
						|
                    for (i=0; i<def["fields"].length; i++) {
 | 
						|
                        if (!Builder.isValidMessageField(def["fields"][i])) {
 | 
						|
                            return false;
 | 
						|
                        }
 | 
						|
                        id = parseInt(def["id"], 10);
 | 
						|
                        if (ids.indexOf(id) >= 0) {
 | 
						|
                            return false;
 | 
						|
                        }
 | 
						|
                        ids.push(id);
 | 
						|
                    }
 | 
						|
                    ids = null;
 | 
						|
                }
 | 
						|
                if (typeof def["enums"] !== 'undefined') {
 | 
						|
                    if (!ProtoBuf.Util.isArray(def["enums"])) {
 | 
						|
                        return false;
 | 
						|
                    }
 | 
						|
                    for (i=0; i<def["enums"].length; i++) {
 | 
						|
                        if (!Builder.isValidEnum(def["enums"][i])) {
 | 
						|
                            return false;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                if (typeof def["messages"] !== 'undefined') {
 | 
						|
                    if (!ProtoBuf.Util.isArray(def["messages"])) {
 | 
						|
                        return false;
 | 
						|
                    }
 | 
						|
                    for (i=0; i<def["messages"].length; i++) {
 | 
						|
                        if (!Builder.isValidMessage(def["messages"][i]) && !Builder.isValidExtend(def["messages"][i])) {
 | 
						|
                            return false;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                if (typeof def["extensions"] !== 'undefined') {
 | 
						|
                    if (!ProtoBuf.Util.isArray(def["extensions"]) || def["extensions"].length !== 2 || typeof def["extensions"][0] !== 'number' || typeof def["extensions"][1] !== 'number') {
 | 
						|
                        return false;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                return true;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Tests if a definition is a valid message field definition.
 | 
						|
             * @param {Object} def Definition
 | 
						|
             * @return {boolean} true if valid, else false
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Builder.isValidMessageField = function(def) {
 | 
						|
                // Message fields require a string rule, name and type and an id
 | 
						|
                if (typeof def["rule"] !== 'string' || typeof def["name"] !== 'string' || typeof def["type"] !== 'string' || typeof def["id"] === 'undefined') {
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
                if (!Lang.RULE.test(def["rule"]) || !Lang.NAME.test(def["name"]) || !Lang.TYPEREF.test(def["type"]) || !Lang.ID.test(""+def["id"])) {
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
                if (typeof def["options"] != 'undefined') {
 | 
						|
                    // Options are objects
 | 
						|
                    if (typeof def["options"] != 'object') {
 | 
						|
                        return false;
 | 
						|
                    }
 | 
						|
                    // Options are <string,*>
 | 
						|
                    var keys = Object.keys(def["options"]);
 | 
						|
                    for (var i=0; i<keys.length; i++) {
 | 
						|
                        if (!Lang.OPTNAME.test(keys[i]) || (typeof def["options"][keys[i]] !== 'string' && typeof def["options"][keys[i]] !== 'number' && typeof def["options"][keys[i]] !== 'boolean')) {
 | 
						|
                            return false;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                return true;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Tests if a definition is a valid enum definition.
 | 
						|
             * @param {Object} def Definition
 | 
						|
             * @return {boolean} true if valid, else false
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Builder.isValidEnum = function(def) {
 | 
						|
                // Enums require a string name
 | 
						|
                if (typeof def["name"] !== 'string' || !Lang.NAME.test(def["name"])) {
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
                // Enums require at least one value
 | 
						|
                if (typeof def["values"] === 'undefined' || !ProtoBuf.Util.isArray(def["values"]) || def["values"].length == 0) {
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
                for (var i=0; i<def["values"].length; i++) {
 | 
						|
                    // Values are objects
 | 
						|
                    if (typeof def["values"][i] != "object") {
 | 
						|
                        return false;
 | 
						|
                    }
 | 
						|
                    // Values require a string name and an id
 | 
						|
                    if (typeof def["values"][i]["name"] !== 'string' || typeof def["values"][i]["id"] === 'undefined') {
 | 
						|
                        return false;
 | 
						|
                    }
 | 
						|
                    if (!Lang.NAME.test(def["values"][i]["name"]) || !Lang.NEGID.test(""+def["values"][i]["id"])) {
 | 
						|
                        return false;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                // It's not important if there are other fields because ["values"] is already unique
 | 
						|
                return true;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Creates ths specified protocol types at the current pointer position.
 | 
						|
             * @param {Array.<Object.<string,*>>} defs Messages, enums or services to create
 | 
						|
             * @return {ProtoBuf.Builder} this
 | 
						|
             * @throws {Error} If a message definition is invalid
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Builder.prototype.create = function(defs) {
 | 
						|
                if (!defs) return; // Nothing to create
 | 
						|
                if (!ProtoBuf.Util.isArray(defs)) {
 | 
						|
                    defs = [defs];
 | 
						|
                }
 | 
						|
                if (defs.length == 0) return;
 | 
						|
                
 | 
						|
                // It's quite hard to keep track of scopes and memory here, so let's do this iteratively.
 | 
						|
                var stack = [], def, obj, subObj, i, j;
 | 
						|
                stack.push(defs); // One level [a, b, c]
 | 
						|
                while (stack.length > 0) {
 | 
						|
                    defs = stack.pop();
 | 
						|
                    if (ProtoBuf.Util.isArray(defs)) { // Stack always contains entire namespaces
 | 
						|
                        while (defs.length > 0) {
 | 
						|
                            def = defs.shift(); // Namespace always contains an array of messages, enums and services
 | 
						|
                            if (Builder.isValidMessage(def)) {
 | 
						|
                                obj = new Reflect.Message(this.ptr, def["name"], def["options"]);
 | 
						|
                                // Create fields
 | 
						|
                                if (def["fields"] && def["fields"].length > 0) {
 | 
						|
                                    for (i=0; i<def["fields"].length; i++) { // i=Fields
 | 
						|
                                        if (obj.hasChild(def['fields'][i]['id'])) {
 | 
						|
                                            throw(new Error("Duplicate field id in message "+obj.name+": "+def['fields'][i]['id']));
 | 
						|
                                        }
 | 
						|
                                        if (def["fields"][i]["options"]) {
 | 
						|
                                            subObj = Object.keys(def["fields"][i]["options"]);
 | 
						|
                                            for (j=0; j<subObj.length; j++) { // j=Option names
 | 
						|
                                                if (!Lang.OPTNAME.test(subObj[j])) {
 | 
						|
                                                    throw(new Error("Illegal field option name in message "+obj.name+"#"+def["fields"][i]["name"]+": "+subObj[j]));
 | 
						|
                                                }
 | 
						|
                                                if (typeof def["fields"][i]["options"][subObj[j]] !== 'string' && typeof def["fields"][i]["options"][subObj[j]] !== 'number' && typeof def["fields"][i]["options"][subObj[j]] !== 'boolean') {
 | 
						|
                                                    throw(new Error("Illegal field option value in message "+obj.name+"#"+def["fields"][i]["name"]+"#"+subObj[j]+": "+def["fields"][i]["options"][subObj[j]]));
 | 
						|
                                                }
 | 
						|
                                            }
 | 
						|
                                            subObj = null;
 | 
						|
                                        }
 | 
						|
                                        obj.addChild(new Reflect.Message.Field(obj, def["fields"][i]["rule"], def["fields"][i]["type"], def["fields"][i]["name"], def["fields"][i]["id"], def["fields"][i]["options"]));
 | 
						|
                                    }
 | 
						|
                                }
 | 
						|
                                // Push enums and messages to stack
 | 
						|
                                subObj = [];
 | 
						|
                                if (typeof def["enums"] !== 'undefined' && def['enums'].length > 0) {
 | 
						|
                                    for (i=0; i<def["enums"].length; i++) {
 | 
						|
                                        subObj.push(def["enums"][i]);
 | 
						|
                                    }
 | 
						|
                                }
 | 
						|
                                if (def["messages"] && def["messages"].length > 0) {
 | 
						|
                                    for (i=0; i<def["messages"].length; i++) {
 | 
						|
                                        subObj.push(def["messages"][i]);
 | 
						|
                                    }
 | 
						|
                                }
 | 
						|
                                // Set extension range
 | 
						|
                                if (def["extensions"]) {
 | 
						|
                                    obj.extensions = def["extensions"];
 | 
						|
                                    if (obj.extensions[0] < ProtoBuf.Lang.ID_MIN) {
 | 
						|
                                        obj.extensions[0] = ProtoBuf.Lang.ID_MIN;
 | 
						|
                                    }
 | 
						|
                                    if (obj.extensions[1] > ProtoBuf.Lang.ID_MAX) {
 | 
						|
                                        obj.extensions[1] = ProtoBuf.Lang.ID_MAX;
 | 
						|
                                    }
 | 
						|
                                }
 | 
						|
                                this.ptr.addChild(obj); // Add to current namespace
 | 
						|
                                if (subObj.length > 0) {
 | 
						|
                                    stack.push(defs); // Push the current level back
 | 
						|
                                    defs = subObj; // Continue processing sub level
 | 
						|
                                    subObj = null;
 | 
						|
                                    this.ptr = obj; // And move the pointer to this namespace
 | 
						|
                                    obj = null;
 | 
						|
                                    continue;
 | 
						|
                                }
 | 
						|
                                subObj = null;
 | 
						|
                                obj = null;
 | 
						|
                            } else if (Builder.isValidEnum(def)) {
 | 
						|
                                obj = new Reflect.Enum(this.ptr, def["name"], def["options"]);
 | 
						|
                                for (i=0; i<def["values"].length; i++) {
 | 
						|
                                    obj.addChild(new Reflect.Enum.Value(obj, def["values"][i]["name"], def["values"][i]["id"]));
 | 
						|
                                }
 | 
						|
                                this.ptr.addChild(obj);
 | 
						|
                                obj = null;
 | 
						|
                            } else if (Builder.isValidService(def)) {
 | 
						|
                                obj = new Reflect.Service(this.ptr, def["name"], def["options"]);
 | 
						|
                                for (i in def["rpc"]) {
 | 
						|
                                    if (def["rpc"].hasOwnProperty(i)) {
 | 
						|
                                        obj.addChild(new Reflect.Service.RPCMethod(obj, i, def["rpc"][i]["request"], def["rpc"][i]["response"], def["rpc"][i]["options"]));
 | 
						|
                                    }
 | 
						|
                                }
 | 
						|
                                this.ptr.addChild(obj);
 | 
						|
                                obj = null;
 | 
						|
                            } else if (Builder.isValidExtend(def)) {
 | 
						|
                                obj = this.ptr.resolve(def["ref"]);
 | 
						|
                                if (obj) {
 | 
						|
                                    for (i=0; i<def["fields"].length; i++) { // i=Fields
 | 
						|
                                        if (obj.hasChild(def['fields'][i]['id'])) {
 | 
						|
                                            throw(new Error("Duplicate extended field id in message "+obj.name+": "+def['fields'][i]['id']));
 | 
						|
                                        }
 | 
						|
                                        if (def['fields'][i]['id'] < obj.extensions[0] || def['fields'][i]['id'] > obj.extensions[1]) {
 | 
						|
                                            throw(new Error("Illegal extended field id in message "+obj.name+": "+def['fields'][i]['id']+" ("+obj.extensions.join(' to ')+" expected)"));
 | 
						|
                                        }
 | 
						|
                                        obj.addChild(new Reflect.Message.Field(obj, def["fields"][i]["rule"], def["fields"][i]["type"], def["fields"][i]["name"], def["fields"][i]["id"], def["fields"][i]["options"]));
 | 
						|
                                    }
 | 
						|
                                    /* if (this.ptr instanceof Reflect.Message) {
 | 
						|
                                        this.ptr.addChild(obj); // Reference the extended message here to enable proper lookups
 | 
						|
                                    } */
 | 
						|
                                } else {
 | 
						|
                                    if (!/\.?google\.protobuf\./.test(def["ref"])) { // Silently skip internal extensions
 | 
						|
                                        throw(new Error("Extended message "+def["ref"]+" is not defined"));
 | 
						|
                                    }
 | 
						|
                                }
 | 
						|
                            } else {
 | 
						|
                                throw(new Error("Not a valid message, enum, service or extend definition: "+JSON.stringify(def)));
 | 
						|
                            }
 | 
						|
                            def = null;
 | 
						|
                        }
 | 
						|
                        // Break goes here
 | 
						|
                    } else {
 | 
						|
                        throw(new Error("Not a valid namespace definition: "+JSON.stringify(defs)));
 | 
						|
                    }
 | 
						|
                    defs = null;
 | 
						|
                    this.ptr = this.ptr.parent; // This namespace is s done
 | 
						|
                }
 | 
						|
                this.resolved = false; // Require re-resolve
 | 
						|
                this.result = null; // Require re-build
 | 
						|
                return this;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Tests if the specified file is a valid import.
 | 
						|
             * @param {string} filename
 | 
						|
             * @returns {boolean} true if valid, false if it should be skipped
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Builder.isValidImport = function(filename) {
 | 
						|
                // Ignore google/protobuf/descriptor.proto (for example) as it makes use of low-level
 | 
						|
                // bootstrapping directives that are not required and therefore cannot be parsed by ProtoBuf.js.
 | 
						|
                return !(/google\/protobuf\//.test(filename));
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Imports another definition into this builder.
 | 
						|
             * @param {Object.<string,*>} json Parsed import
 | 
						|
             * @param {(string|{root: string, file: string})=} filename Imported file name
 | 
						|
             * @return {ProtoBuf.Builder} this
 | 
						|
             * @throws {Error} If the definition or file cannot be imported
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Builder.prototype["import"] = function(json, filename) {
 | 
						|
                if (typeof filename === 'string') {
 | 
						|
                    if (ProtoBuf.Util.IS_NODE) {
 | 
						|
                        var path = require("path");
 | 
						|
                        filename = path.resolve(filename);
 | 
						|
                    }
 | 
						|
                    if (!!this.files[filename]) {
 | 
						|
                        this.reset();
 | 
						|
                        return this; // Skip duplicate imports
 | 
						|
                    }
 | 
						|
                    this.files[filename] = true;
 | 
						|
                }
 | 
						|
                if (!!json['imports'] && json['imports'].length > 0) {
 | 
						|
                    var importRoot, delim = '/', resetRoot = false;
 | 
						|
                    if (typeof filename === 'object') { // If an import root is specified, override
 | 
						|
                        this.importRoot = filename["root"]; resetRoot = true; // ... and reset afterwards
 | 
						|
                        importRoot = this.importRoot;
 | 
						|
                        filename = filename["file"];
 | 
						|
                        if (importRoot.indexOf("\\") >= 0 || filename.indexOf("\\") >= 0) delim = '\\';
 | 
						|
                    } else if (typeof filename === 'string') {
 | 
						|
                        if (this.importRoot) { // If import root is overridden, use it
 | 
						|
                            importRoot = this.importRoot;
 | 
						|
                        } else { // Otherwise compute from filename
 | 
						|
                            if (filename.indexOf("/") >= 0) { // Unix
 | 
						|
                                importRoot = filename.replace(/\/[^\/]*$/, "");
 | 
						|
                                if (/* /file.proto */ importRoot === "") importRoot = "/";
 | 
						|
                            } else if (filename.indexOf("\\") >= 0) { // Windows
 | 
						|
                                importRoot = filename.replace(/\\[^\\]*$/, ""); delim = '\\';
 | 
						|
                            } else {
 | 
						|
                                importRoot = ".";
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    } else {
 | 
						|
                        importRoot = null;
 | 
						|
                    }
 | 
						|
        
 | 
						|
                    for (var i=0; i<json['imports'].length; i++) {
 | 
						|
                        if (typeof json['imports'][i] === 'string') { // Import file
 | 
						|
                            if (!importRoot) {
 | 
						|
                                throw(new Error("Cannot determine import root: File name is unknown"));
 | 
						|
                            }
 | 
						|
                            var importFilename = importRoot+delim+json['imports'][i];
 | 
						|
                            if (!Builder.isValidImport(importFilename)) continue; // e.g. google/protobuf/*
 | 
						|
                            if (/\.proto$/i.test(importFilename) && !ProtoBuf.DotProto) {     // If this is a NOPARSE build
 | 
						|
                                importFilename = importFilename.replace(/\.proto$/, ".json"); // always load the JSON file
 | 
						|
                            }
 | 
						|
                            var contents = ProtoBuf.Util.fetch(importFilename);
 | 
						|
                            if (contents === null) {
 | 
						|
                                throw(new Error("Failed to import '"+importFilename+"' in '"+filename+"': File not found"));
 | 
						|
                            }
 | 
						|
                            if (/\.json$/i.test(importFilename)) { // Always possible
 | 
						|
                                this["import"](JSON.parse(contents+""), importFilename); // May throw
 | 
						|
                            } else {
 | 
						|
                                this["import"]((new ProtoBuf.DotProto.Parser(contents+"")).parse(), importFilename); // May throw
 | 
						|
                            }
 | 
						|
                        } else { // Import structure
 | 
						|
                            if (!filename) {
 | 
						|
                                this["import"](json['imports'][i]);
 | 
						|
                            } else if (/\.(\w+)$/.test(filename)) { // With extension: Append _importN to the name portion to make it unique
 | 
						|
                                this["import"](json['imports'][i], filename.replace(/^(.+)\.(\w+)$/, function($0, $1, $2) { return $1+"_import"+i+"."+$2; }));
 | 
						|
                            } else { // Without extension: Append _importN to make it unique
 | 
						|
                                this["import"](json['imports'][i], filename+"_import"+i);
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    if (resetRoot) { // Reset import root override when all imports are done
 | 
						|
                        this.importRoot = null;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                if (!!json['messages']) {
 | 
						|
                    if (!!json['package']) this.define(json['package'], json["options"]);
 | 
						|
                    this.create(json['messages']);
 | 
						|
                    this.reset();
 | 
						|
                }
 | 
						|
                if (!!json['enums']) {
 | 
						|
                    if (!!json['package']) this.define(json['package'], json["options"]);
 | 
						|
                    this.create(json['enums']);
 | 
						|
                    this.reset();
 | 
						|
                }
 | 
						|
                if (!!json['services']) {
 | 
						|
                    if (!!json['package']) this.define(json['package'], json["options"]);
 | 
						|
                    this.create(json['services']);
 | 
						|
                    this.reset();
 | 
						|
                }
 | 
						|
                if (!!json['extends']) {
 | 
						|
                    if (!!json['package']) this.define(json['package'], json["options"]);
 | 
						|
                    this.create(json['extends']);
 | 
						|
                    this.reset();
 | 
						|
                }
 | 
						|
                return this;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Tests if a definition is a valid service definition.
 | 
						|
             * @param {Object} def Definition
 | 
						|
             * @return {boolean} true if valid, else false
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Builder.isValidService = function(def) {
 | 
						|
                // Services require a string name
 | 
						|
                if (typeof def["name"] !== 'string' || !Lang.NAME.test(def["name"]) || typeof def["rpc"] !== 'object') {
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
                return true;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Tests if a definition is a valid extension.
 | 
						|
             * @param {Object} def Definition
 | 
						|
             * @returns {boolean} true if valid, else false
 | 
						|
             * @expose
 | 
						|
            */
 | 
						|
            Builder.isValidExtend = function(def) {
 | 
						|
                if (typeof def["ref"] !== 'string' || !Lang.TYPEREF.test(def["name"])) {
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
                var i;
 | 
						|
                if (typeof def["fields"] !== 'undefined') {
 | 
						|
                    if (!ProtoBuf.Util.isArray(def["fields"])) {
 | 
						|
                        return false;
 | 
						|
                    }
 | 
						|
                    var ids = [], id; // IDs must be unique (does not yet test for the extended message's ids)
 | 
						|
                    for (i=0; i<def["fields"].length; i++) {
 | 
						|
                        if (!Builder.isValidMessageField(def["fields"][i])) {
 | 
						|
                            return false;
 | 
						|
                        }
 | 
						|
                        id = parseInt(def["id"], 10);
 | 
						|
                        if (ids.indexOf(id) >= 0) {
 | 
						|
                            return false;
 | 
						|
                        }
 | 
						|
                        ids.push(id);
 | 
						|
                    }
 | 
						|
                    ids = null;
 | 
						|
                }
 | 
						|
                return true;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Resolves all namespace objects.
 | 
						|
             * @throws {Error} If a type cannot be resolved
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Builder.prototype.resolveAll = function() {
 | 
						|
                // Resolve all reflected objects
 | 
						|
                var res;
 | 
						|
                if (this.ptr == null || typeof this.ptr.type === 'object') return; // Done (already resolved)
 | 
						|
                if (this.ptr instanceof Reflect.Namespace) {
 | 
						|
                    // Build all children
 | 
						|
                    var children = this.ptr.getChildren();
 | 
						|
                    for (var i=0; i<children.length; i++) {
 | 
						|
                        this.ptr = children[i];
 | 
						|
                        this.resolveAll();
 | 
						|
                    }
 | 
						|
                } else if (this.ptr instanceof Reflect.Message.Field) {
 | 
						|
                    if (!Lang.TYPE.test(this.ptr.type)) { // Resolve type...
 | 
						|
                        if (!Lang.TYPEREF.test(this.ptr.type)) {
 | 
						|
                            throw(new Error("Illegal type reference in "+this.ptr.toString(true)+": "+this.ptr.type));
 | 
						|
                        }
 | 
						|
                        res = this.ptr.parent.resolve(this.ptr.type, true);
 | 
						|
                        if (!res) {
 | 
						|
                            throw(new Error("Unresolvable type reference in "+this.ptr.toString(true)+": "+this.ptr.type));
 | 
						|
                        }
 | 
						|
                        this.ptr.resolvedType = res;
 | 
						|
                        if (res instanceof Reflect.Enum) {
 | 
						|
                            this.ptr.type = ProtoBuf.TYPES["enum"];
 | 
						|
                        } else if (res instanceof Reflect.Message) {
 | 
						|
                            this.ptr.type = ProtoBuf.TYPES["message"];
 | 
						|
                        } else {
 | 
						|
                            throw(new Error("Illegal type reference in "+this.ptr.toString(true)+": "+this.ptr.type));
 | 
						|
                        }
 | 
						|
                    } else {
 | 
						|
                        this.ptr.type = ProtoBuf.TYPES[this.ptr.type];
 | 
						|
                    }
 | 
						|
                } else if (this.ptr instanceof ProtoBuf.Reflect.Enum.Value) {
 | 
						|
                    // No need to build enum values (built in enum)
 | 
						|
                } else if (this.ptr instanceof ProtoBuf.Reflect.Service.Method) {
 | 
						|
                    if (this.ptr instanceof ProtoBuf.Reflect.Service.RPCMethod) {
 | 
						|
                        res = this.ptr.parent.resolve(this.ptr.requestName);
 | 
						|
                        if (!res || !(res instanceof ProtoBuf.Reflect.Message)) {
 | 
						|
                            throw(new Error("Illegal request type reference in "+this.ptr.toString(true)+": "+this.ptr.requestName));
 | 
						|
                        }
 | 
						|
                        this.ptr.resolvedRequestType = res;
 | 
						|
                        res = this.ptr.parent.resolve(this.ptr.responseName);
 | 
						|
                        if (!res || !(res instanceof ProtoBuf.Reflect.Message)) {
 | 
						|
                            throw(new Error("Illegal response type reference in "+this.ptr.toString(true)+": "+this.ptr.responseName));
 | 
						|
                        }
 | 
						|
                        this.ptr.resolvedResponseType = res;
 | 
						|
                    } else {
 | 
						|
                        // Should not happen as nothing else is implemented
 | 
						|
                        throw(new Error("Illegal service method type in "+this.ptr.toString(true)));
 | 
						|
                    }
 | 
						|
                } else {
 | 
						|
                    throw(new Error("Illegal object type in namespace: "+typeof(this.ptr)+":"+this.ptr));
 | 
						|
                }
 | 
						|
                this.reset();
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Builds the protocol. This will first try to resolve all definitions and, if this has been successful,
 | 
						|
             * return the built package.
 | 
						|
             * @param {string=} path Specifies what to return. If omitted, the entire namespace will be returned.
 | 
						|
             * @return {ProtoBuf.Builder.Message|Object.<string,*>}
 | 
						|
             * @throws {Error} If a type could not be resolved
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Builder.prototype.build = function(path) {
 | 
						|
                this.reset();
 | 
						|
                if (!this.resolved) {
 | 
						|
                    this.resolveAll();
 | 
						|
                    this.resolved = true;
 | 
						|
                    this.result = null; // Require re-build
 | 
						|
                }
 | 
						|
                if (this.result == null) { // (Re-)Build
 | 
						|
                    this.result = this.ns.build();
 | 
						|
                }
 | 
						|
                if (!path) {
 | 
						|
                    return this.result;
 | 
						|
                } else {
 | 
						|
                    var part = path.split(".");
 | 
						|
                    var ptr = this.result; // Build namespace pointer (no hasChild etc.)
 | 
						|
                    for (var i=0; i<part.length; i++) {
 | 
						|
                        if (ptr[part[i]]) {
 | 
						|
                            ptr = ptr[part[i]];
 | 
						|
                        } else {
 | 
						|
                            ptr = null;
 | 
						|
                            break;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    return ptr;
 | 
						|
                }
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Similar to {@link ProtoBuf.Builder#build}, but looks up the internal reflection descriptor.
 | 
						|
             * @param {string=} path Specifies what to return. If omitted, the entire namespace wiil be returned.
 | 
						|
             * @return {ProtoBuf.Reflect.T} Reflection descriptor or `null` if not found
 | 
						|
             */
 | 
						|
            Builder.prototype.lookup = function(path) {
 | 
						|
                return path ? this.ns.resolve(path) : this.ns;
 | 
						|
            };
 | 
						|
        
 | 
						|
            /**
 | 
						|
             * Returns a string representation of this object.
 | 
						|
             * @return {string} String representation as of "Builder"
 | 
						|
             * @expose
 | 
						|
             */
 | 
						|
            Builder.prototype.toString = function() {
 | 
						|
                return "Builder";
 | 
						|
            };
 | 
						|
        
 | 
						|
            // Pseudo types documented in Reflect.js.
 | 
						|
            // Exist for the sole purpose of being able to "... instanceof ProtoBuf.Builder.Message" etc.
 | 
						|
            Builder.Message = function() {};
 | 
						|
            Builder.Service = function() {};
 | 
						|
            
 | 
						|
            return Builder;
 | 
						|
            
 | 
						|
        })(ProtoBuf, ProtoBuf.Lang, ProtoBuf.Reflect);
 | 
						|
        
 | 
						|
        
 | 
						|
        /**
 | 
						|
         * Loads a .proto string and returns the Builder.
 | 
						|
         * @param {string} proto .proto file contents
 | 
						|
         * @param {(ProtoBuf.Builder|string|{root: string, file: string})=} builder Builder to append to. Will create a new one if omitted.
 | 
						|
         * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports.
 | 
						|
         * @return {ProtoBuf.Builder} Builder to create new messages
 | 
						|
         * @throws {Error} If the definition cannot be parsed or built
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.loadProto = function(proto, builder, filename) {
 | 
						|
            if (typeof builder == 'string' || (builder && typeof builder["file"] === 'string' && typeof builder["root"] === 'string')) {
 | 
						|
                filename = builder;
 | 
						|
                builder = null;
 | 
						|
            }
 | 
						|
            return ProtoBuf.loadJson((new ProtoBuf.DotProto.Parser(proto+"")).parse(), builder, filename);
 | 
						|
        };
 | 
						|
 | 
						|
        /**
 | 
						|
         * Loads a .proto string and returns the Builder. This is an alias of {@link ProtoBuf.loadProto}.
 | 
						|
         * @function
 | 
						|
         * @param {string} proto .proto file contents
 | 
						|
         * @param {(ProtoBuf.Builder|string)=} builder Builder to append to. Will create a new one if omitted.
 | 
						|
         * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports.
 | 
						|
         * @return {ProtoBuf.Builder} Builder to create new messages
 | 
						|
         * @throws {Error} If the definition cannot be parsed or built
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.protoFromString = ProtoBuf.loadProto; // Legacy
 | 
						|
 | 
						|
        /**
 | 
						|
         * Loads a .proto file and returns the Builder.
 | 
						|
         * @param {string|{root: string, file: string}} filename Path to proto file or an object specifying 'file' with
 | 
						|
         *  an overridden 'root' path for all imported files.
 | 
						|
         * @param {function(ProtoBuf.Builder)=} callback Callback that will receive the Builder as its first argument.
 | 
						|
         *   If the request has failed, builder will be NULL. If omitted, the file will be read synchronously and this
 | 
						|
         *   function will return the Builder or NULL if the request has failed.
 | 
						|
         * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted.
 | 
						|
         * @return {?ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the
 | 
						|
         *   request has failed), else undefined
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.loadProtoFile = function(filename, callback, builder) {
 | 
						|
            if (callback && typeof callback === 'object') {
 | 
						|
                builder = callback;
 | 
						|
                callback = null;
 | 
						|
            } else if (!callback || typeof callback !== 'function') {
 | 
						|
                callback = null;
 | 
						|
            }
 | 
						|
            if (callback) {
 | 
						|
                ProtoBuf.Util.fetch(typeof filename === 'object' ? filename["root"]+"/"+filename["file"] : filename, function(contents) {
 | 
						|
                    callback(ProtoBuf.loadProto(contents, builder, filename));
 | 
						|
                });
 | 
						|
            } else {
 | 
						|
                var contents = ProtoBuf.Util.fetch(typeof filename === 'object' ? filename["root"]+"/"+filename["file"] : filename);
 | 
						|
                return contents !== null ? ProtoBuf.protoFromString(contents, builder, filename) : null;
 | 
						|
            }
 | 
						|
        };
 | 
						|
 | 
						|
        /**
 | 
						|
         * Loads a .proto file and returns the Builder. This is an alias of {@link ProtoBuf.loadProtoFile}.
 | 
						|
         * @function
 | 
						|
         * @param {string|{root: string, file: string}} filename Path to proto file or an object specifying 'file' with
 | 
						|
         *  an overridden 'root' path for all imported files.
 | 
						|
         * @param {function(ProtoBuf.Builder)=} callback Callback that will receive the Builder as its first argument.
 | 
						|
         *   If the request has failed, builder will be NULL. If omitted, the file will be read synchronously and this
 | 
						|
         *   function will return the Builder or NULL if the request has failed.
 | 
						|
         * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted.
 | 
						|
         * @return {?ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the
 | 
						|
         *   request has failed), else undefined
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.protoFromFile = ProtoBuf.loadProtoFile; // Legacy
 | 
						|
 | 
						|
 | 
						|
        /**
 | 
						|
         * Constructs a new Builder with the specified package defined.
 | 
						|
         * @param {string=} pkg Package name as fully qualified name, e.g. "My.Game". If no package is specified, the
 | 
						|
         * builder will only contain a global namespace.
 | 
						|
         * @param {Object.<string,*>=} options Top level options
 | 
						|
         * @return {ProtoBuf.Builder} New Builder
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.newBuilder = function(pkg, options) {
 | 
						|
            var builder = new ProtoBuf.Builder();
 | 
						|
            if (typeof pkg !== 'undefined' && pkg !== null) {
 | 
						|
                builder.define(pkg, options);
 | 
						|
            }
 | 
						|
            return builder;
 | 
						|
        };
 | 
						|
 | 
						|
        /**
 | 
						|
         * Loads a .json definition and returns the Builder.
 | 
						|
         * @param {!*|string} json JSON definition
 | 
						|
         * @param {(ProtoBuf.Builder|string|{root: string, file: string})=} builder Builder to append to. Will create a new one if omitted.
 | 
						|
         * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports.
 | 
						|
         * @return {ProtoBuf.Builder} Builder to create new messages
 | 
						|
         * @throws {Error} If the definition cannot be parsed or built
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.loadJson = function(json, builder, filename) {
 | 
						|
            if (typeof builder === 'string' || (builder && typeof builder["file"] === 'string' && typeof builder["root"] === 'string')) {
 | 
						|
                filename = builder;
 | 
						|
                builder = null;
 | 
						|
            }
 | 
						|
            if (!builder || typeof builder !== 'object') builder = ProtoBuf.newBuilder();
 | 
						|
            if (typeof json === 'string') json = JSON.parse(json);
 | 
						|
            builder["import"](json, filename);
 | 
						|
            builder.resolveAll();
 | 
						|
            builder.build();
 | 
						|
            return builder;
 | 
						|
        };
 | 
						|
 | 
						|
        /**
 | 
						|
         * Loads a .json file and returns the Builder.
 | 
						|
         * @param {string|{root: string, file: string}} filename Path to json file or an object specifying 'file' with
 | 
						|
         *  an overridden 'root' path for all imported files.
 | 
						|
         * @param {function(ProtoBuf.Builder)=} callback Callback that will receive the Builder as its first argument.
 | 
						|
         *   If the request has failed, builder will be NULL. If omitted, the file will be read synchronously and this
 | 
						|
         *   function will return the Builder or NULL if the request has failed.
 | 
						|
         * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted.
 | 
						|
         * @return {?ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the
 | 
						|
         *   request has failed), else undefined
 | 
						|
         * @expose
 | 
						|
         */
 | 
						|
        ProtoBuf.loadJsonFile = function(filename, callback, builder) {
 | 
						|
            if (callback && typeof callback === 'object') {
 | 
						|
                builder = callback;
 | 
						|
                callback = null;
 | 
						|
            } else if (!callback || typeof callback !== 'function') {
 | 
						|
                callback = null;
 | 
						|
            }
 | 
						|
            if (callback) {
 | 
						|
                ProtoBuf.Util.fetch(typeof filename === 'object' ? filename["root"]+"/"+filename["file"] : filename, function(contents) {
 | 
						|
                    try {
 | 
						|
                        callback(ProtoBuf.loadJson(JSON.parse(contents), builder, filename));
 | 
						|
                    } catch (err) {
 | 
						|
                        callback(err);
 | 
						|
                    }
 | 
						|
                });
 | 
						|
            } else {
 | 
						|
                var contents = ProtoBuf.Util.fetch(typeof filename === 'object' ? filename["root"]+"/"+filename["file"] : filename);
 | 
						|
                return contents !== null ? ProtoBuf.loadJson(JSON.parse(contents), builder, filename) : null;
 | 
						|
            }
 | 
						|
        };
 | 
						|
 | 
						|
        return ProtoBuf;
 | 
						|
    }
 | 
						|
 | 
						|
    // Enable module loading if available
 | 
						|
    if (typeof module != 'undefined' && module["exports"]) { // CommonJS
 | 
						|
        module["exports"] = loadProtoBuf(require("bytebuffer"));
 | 
						|
    } else if (typeof define != 'undefined' && define["amd"]) { // AMD
 | 
						|
        define("ProtoBuf", ["ByteBuffer"], loadProtoBuf);
 | 
						|
    } else { // Shim
 | 
						|
        if (!global["dcodeIO"]) {
 | 
						|
            global["dcodeIO"] = {};
 | 
						|
        }
 | 
						|
        global["dcodeIO"]["ProtoBuf"] = loadProtoBuf(global["dcodeIO"]["ByteBuffer"]);
 | 
						|
    }
 | 
						|
 | 
						|
})(this); |