2 Copyright 2013 Daniel Wirtz <dcode@dcode.io>
\r
4 Licensed under the Apache License, Version 2.0 (the "License");
\r
5 you may not use this file except in compliance with the License.
\r
6 You may obtain a copy of the License at
\r
8 http://www.apache.org/licenses/LICENSE-2.0
\r
10 Unless required by applicable law or agreed to in writing, software
\r
11 distributed under the License is distributed on an "AS IS" BASIS,
\r
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 See the License for the specific language governing permissions and
\r
14 limitations under the License.
\r
18 * @license protobuf.js (c) 2013 Daniel Wirtz <dcode@dcode.io>
\r
19 * Released under the Apache License, Version 2.0
\r
20 * see: https://github.com/dcodeIO/protobuf.js for details
\r
22 (function(global, factory) {
\r
24 /* AMD */ if (typeof define === 'function' && define["amd"])
\r
25 define(["bytebuffer"], factory);
\r
26 /* CommonJS */ else if (typeof require === "function" && typeof module === "object" && module && module["exports"])
\r
27 module["exports"] = factory(require("bytebuffer"), true);
\r
29 (global["dcodeIO"] = global["dcodeIO"] || {})["ProtoBuf"] = factory(global["dcodeIO"]["ByteBuffer"]);
\r
31 })(this, function(ByteBuffer, isCommonJS) {
\r
35 * The ProtoBuf namespace.
\r
43 * @type {!function(new: ByteBuffer, ...[*])}
\r
46 ProtoBuf.ByteBuffer = ByteBuffer;
\r
49 * @type {?function(new: Long, ...[*])}
\r
52 ProtoBuf.Long = ByteBuffer.Long || null;
\r
55 * ProtoBuf.js version.
\r
60 ProtoBuf.VERSION = "5.0.3";
\r
64 * @type {Object.<string,number>}
\r
68 ProtoBuf.WIRE_TYPES = {};
\r
75 ProtoBuf.WIRE_TYPES.VARINT = 0;
\r
78 * Fixed 64 bits wire type.
\r
83 ProtoBuf.WIRE_TYPES.BITS64 = 1;
\r
86 * Length delimited wire type.
\r
91 ProtoBuf.WIRE_TYPES.LDELIM = 2;
\r
94 * Start group wire type.
\r
99 ProtoBuf.WIRE_TYPES.STARTGROUP = 3;
\r
102 * End group wire type.
\r
107 ProtoBuf.WIRE_TYPES.ENDGROUP = 4;
\r
110 * Fixed 32 bits wire type.
\r
115 ProtoBuf.WIRE_TYPES.BITS32 = 5;
\r
118 * Packable wire types.
\r
119 * @type {!Array.<number>}
\r
123 ProtoBuf.PACKABLE_WIRE_TYPES = [
\r
124 ProtoBuf.WIRE_TYPES.VARINT,
\r
125 ProtoBuf.WIRE_TYPES.BITS64,
\r
126 ProtoBuf.WIRE_TYPES.BITS32
\r
132 * @type {!Object.<string,{name: string, wireType: number, defaultValue: *}>}
\r
137 // According to the protobuf spec.
\r
140 wireType: ProtoBuf.WIRE_TYPES.VARINT,
\r
145 wireType: ProtoBuf.WIRE_TYPES.VARINT,
\r
150 wireType: ProtoBuf.WIRE_TYPES.VARINT,
\r
155 wireType: ProtoBuf.WIRE_TYPES.VARINT,
\r
156 defaultValue: ProtoBuf.Long ? ProtoBuf.Long.ZERO : undefined
\r
160 wireType: ProtoBuf.WIRE_TYPES.VARINT,
\r
161 defaultValue: ProtoBuf.Long ? ProtoBuf.Long.UZERO : undefined
\r
165 wireType: ProtoBuf.WIRE_TYPES.VARINT,
\r
166 defaultValue: ProtoBuf.Long ? ProtoBuf.Long.ZERO : undefined
\r
170 wireType: ProtoBuf.WIRE_TYPES.VARINT,
\r
171 defaultValue: false
\r
175 wireType: ProtoBuf.WIRE_TYPES.BITS64,
\r
180 wireType: ProtoBuf.WIRE_TYPES.LDELIM,
\r
185 wireType: ProtoBuf.WIRE_TYPES.LDELIM,
\r
186 defaultValue: null // overridden in the code, must be a unique instance
\r
190 wireType: ProtoBuf.WIRE_TYPES.BITS32,
\r
195 wireType: ProtoBuf.WIRE_TYPES.BITS32,
\r
200 wireType: ProtoBuf.WIRE_TYPES.BITS64,
\r
201 defaultValue: ProtoBuf.Long ? ProtoBuf.Long.UZERO : undefined
\r
205 wireType: ProtoBuf.WIRE_TYPES.BITS64,
\r
206 defaultValue: ProtoBuf.Long ? ProtoBuf.Long.ZERO : undefined
\r
210 wireType: ProtoBuf.WIRE_TYPES.BITS32,
\r
215 wireType: ProtoBuf.WIRE_TYPES.VARINT,
\r
220 wireType: ProtoBuf.WIRE_TYPES.LDELIM,
\r
225 wireType: ProtoBuf.WIRE_TYPES.STARTGROUP,
\r
231 * Valid map key types.
\r
232 * @type {!Array.<!Object.<string,{name: string, wireType: number, defaultValue: *}>>}
\r
236 ProtoBuf.MAP_KEY_TYPES = [
\r
237 ProtoBuf.TYPES["int32"],
\r
238 ProtoBuf.TYPES["sint32"],
\r
239 ProtoBuf.TYPES["sfixed32"],
\r
240 ProtoBuf.TYPES["uint32"],
\r
241 ProtoBuf.TYPES["fixed32"],
\r
242 ProtoBuf.TYPES["int64"],
\r
243 ProtoBuf.TYPES["sint64"],
\r
244 ProtoBuf.TYPES["sfixed64"],
\r
245 ProtoBuf.TYPES["uint64"],
\r
246 ProtoBuf.TYPES["fixed64"],
\r
247 ProtoBuf.TYPES["bool"],
\r
248 ProtoBuf.TYPES["string"],
\r
249 ProtoBuf.TYPES["bytes"]
\r
253 * Minimum field id.
\r
258 ProtoBuf.ID_MIN = 1;
\r
261 * Maximum field id.
\r
266 ProtoBuf.ID_MAX = 0x1FFFFFFF;
\r
269 * If set to `true`, field names will be converted from underscore notation to camel case. Defaults to `false`.
\r
270 * Must be set prior to parsing.
\r
274 ProtoBuf.convertFieldsToCamelCase = false;
\r
277 * By default, messages are populated with (setX, set_x) accessors for each field. This can be disabled by
\r
278 * setting this to `false` prior to building messages.
\r
282 ProtoBuf.populateAccessors = true;
\r
285 * By default, messages are populated with default values if a field is not present on the wire. To disable
\r
286 * this behavior, set this setting to `false`.
\r
290 ProtoBuf.populateDefaults = true;
\r
293 * @alias ProtoBuf.Util
\r
296 ProtoBuf.Util = (function() {
\r
300 * ProtoBuf utilities.
\r
301 * @exports ProtoBuf.Util
\r
307 * Flag if running in node or not.
\r
313 typeof process === 'object' && process+'' === '[object process]' && !process['browser']
\r
317 * Constructs a XMLHttpRequest object.
\r
318 * @return {XMLHttpRequest}
\r
319 * @throws {Error} If XMLHttpRequest is not supported
\r
322 Util.XHR = function() {
\r
323 // No dependencies please, ref: http://www.quirksmode.org/js/xmlhttp.html
\r
324 var XMLHttpFactories = [
\r
325 function () {return new XMLHttpRequest()},
\r
326 function () {return new ActiveXObject("Msxml2.XMLHTTP")},
\r
327 function () {return new ActiveXObject("Msxml3.XMLHTTP")},
\r
328 function () {return new ActiveXObject("Microsoft.XMLHTTP")}
\r
330 /** @type {?XMLHttpRequest} */
\r
332 for (var i=0;i<XMLHttpFactories.length;i++) {
\r
333 try { xhr = XMLHttpFactories[i](); }
\r
334 catch (e) { continue; }
\r
338 throw Error("XMLHttpRequest is not supported");
\r
343 * Fetches a resource.
\r
344 * @param {string} path Resource path
\r
345 * @param {function(?string)=} callback Callback receiving the resource's contents. If omitted the resource will
\r
346 * be fetched synchronously. If the request failed, contents will be null.
\r
347 * @return {?string|undefined} Resource contents if callback is omitted (null if the request failed), else undefined.
\r
350 Util.fetch = function(path, callback) {
\r
351 if (callback && typeof callback != 'function')
\r
353 if (Util.IS_NODE) {
\r
354 var fs = require("fs");
\r
356 fs.readFile(path, function(err, data) {
\r
364 return fs.readFileSync(path);
\r
369 var xhr = Util.XHR();
\r
370 xhr.open('GET', path, callback ? true : false);
\r
371 // xhr.setRequestHeader('User-Agent', 'XMLHTTP/1.0');
\r
372 xhr.setRequestHeader('Accept', 'text/plain');
\r
373 if (typeof xhr.overrideMimeType === 'function') xhr.overrideMimeType('text/plain');
\r
375 xhr.onreadystatechange = function() {
\r
376 if (xhr.readyState != 4) return;
\r
377 if (/* remote */ xhr.status == 200 || /* local */ (xhr.status == 0 && typeof xhr.responseText === 'string'))
\r
378 callback(xhr.responseText);
\r
382 if (xhr.readyState == 4)
\r
387 if (/* remote */ xhr.status == 200 || /* local */ (xhr.status == 0 && typeof xhr.responseText === 'string'))
\r
388 return xhr.responseText;
\r
395 * Converts a string to camel case.
\r
396 * @param {string} str
\r
397 * @returns {string}
\r
400 Util.toCamelCase = function(str) {
\r
401 return str.replace(/_([a-zA-Z])/g, function ($0, $1) {
\r
402 return $1.toUpperCase();
\r
410 * Language expressions.
\r
411 * @type {!Object.<string,!RegExp>}
\r
416 // Characters always ending a statement
\r
417 DELIM: /[\s\{\}=;:\[\],'"\(\)<>]/g,
\r
420 RULE: /^(?:required|optional|repeated|map)$/,
\r
423 TYPE: /^(?:double|float|int32|uint32|sint32|int64|uint64|sint64|fixed32|sfixed32|fixed64|sfixed64|bool|string|bytes)$/,
\r
426 NAME: /^[a-zA-Z_][a-zA-Z_0-9]*$/,
\r
428 // Type definitions
\r
429 TYPEDEF: /^[a-zA-Z][a-zA-Z_0-9]*$/,
\r
432 TYPEREF: /^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*$/,
\r
434 // Fully qualified type references
\r
435 FQTYPEREF: /^(?:\.[a-zA-Z_][a-zA-Z_0-9]*)+$/,
\r
438 NUMBER: /^-?(?:[1-9][0-9]*|0|0[xX][0-9a-fA-F]+|0[0-7]+|([0-9]*(\.[0-9]*)?([Ee][+-]?[0-9]+)?)|inf|nan)$/,
\r
441 NUMBER_DEC: /^(?:[1-9][0-9]*|0)$/,
\r
443 // Hexadecimal numbers
\r
444 NUMBER_HEX: /^0[xX][0-9a-fA-F]+$/,
\r
447 NUMBER_OCT: /^0[0-7]+$/,
\r
449 // Floating point numbers
\r
450 NUMBER_FLT: /^([0-9]*(\.[0-9]*)?([Ee][+-]?[0-9]+)?|inf|nan)$/,
\r
453 BOOL: /^(?:true|false)$/i,
\r
456 ID: /^(?:[1-9][0-9]*|0|0[xX][0-9a-fA-F]+|0[0-7]+)$/,
\r
458 // Negative id numbers (enum values)
\r
459 NEGID: /^\-?(?:[1-9][0-9]*|0|0[xX][0-9a-fA-F]+|0[0-7]+)$/,
\r
465 STRING: /(?:"([^"\\]*(?:\\.[^"\\]*)*)")|(?:'([^'\\]*(?:\\.[^'\\]*)*)')/g,
\r
467 // Double quoted strings
\r
468 STRING_DQ: /(?:"([^"\\]*(?:\\.[^"\\]*)*)")/g,
\r
470 // Single quoted strings
\r
471 STRING_SQ: /(?:'([^'\\]*(?:\\.[^'\\]*)*)')/g
\r
476 * @alias ProtoBuf.Reflect
\r
479 ProtoBuf.Reflect = (function(ProtoBuf) {
\r
483 * Reflection types.
\r
484 * @exports ProtoBuf.Reflect
\r
490 * Constructs a Reflect base class.
\r
491 * @exports ProtoBuf.Reflect.T
\r
494 * @param {!ProtoBuf.Builder} builder Builder reference
\r
495 * @param {?ProtoBuf.Reflect.T} parent Parent object
\r
496 * @param {string} name Object name
\r
498 var T = function(builder, parent, name) {
\r
501 * Builder reference.
\r
502 * @type {!ProtoBuf.Builder}
\r
505 this.builder = builder;
\r
509 * @type {?ProtoBuf.Reflect.T}
\r
512 this.parent = parent;
\r
515 * Object name in namespace.
\r
522 * Fully qualified class name
\r
530 * @alias ProtoBuf.Reflect.T.prototype
\r
533 var TPrototype = T.prototype;
\r
536 * Returns the fully qualified name of this object.
\r
537 * @returns {string} Fully qualified name as of ".PATH.TO.THIS"
\r
540 TPrototype.fqn = function() {
\r
541 var name = this.name,
\r
547 name = ptr.name+"."+name;
\r
553 * Returns a string representation of this Reflect object (its fully qualified name).
\r
554 * @param {boolean=} includeClass Set to true to include the class name. Defaults to false.
\r
555 * @return String representation
\r
558 TPrototype.toString = function(includeClass) {
\r
559 return (includeClass ? this.className + " " : "") + this.fqn();
\r
563 * Builds this type.
\r
564 * @throws {Error} If this type cannot be built directly
\r
567 TPrototype.build = function() {
\r
568 throw Error(this.toString(true)+" cannot be built directly");
\r
572 * @alias ProtoBuf.Reflect.T
\r
578 * Constructs a new Namespace.
\r
579 * @exports ProtoBuf.Reflect.Namespace
\r
580 * @param {!ProtoBuf.Builder} builder Builder reference
\r
581 * @param {?ProtoBuf.Reflect.Namespace} parent Namespace parent
\r
582 * @param {string} name Namespace name
\r
583 * @param {Object.<string,*>=} options Namespace options
\r
584 * @param {string?} syntax The syntax level of this definition (e.g., proto3)
\r
586 * @extends ProtoBuf.Reflect.T
\r
588 var Namespace = function(builder, parent, name, options, syntax) {
\r
589 T.call(this, builder, parent, name);
\r
594 this.className = "Namespace";
\r
597 * Children inside the namespace.
\r
598 * @type {!Array.<ProtoBuf.Reflect.T>}
\r
600 this.children = [];
\r
604 * @type {!Object.<string, *>}
\r
606 this.options = options || {};
\r
609 * Syntax level (e.g., proto2 or proto3).
\r
612 this.syntax = syntax || "proto2";
\r
616 * @alias ProtoBuf.Reflect.Namespace.prototype
\r
619 var NamespacePrototype = Namespace.prototype = Object.create(T.prototype);
\r
622 * Returns an array of the namespace's children.
\r
623 * @param {ProtoBuf.Reflect.T=} type Filter type (returns instances of this type only). Defaults to null (all children).
\r
624 * @return {Array.<ProtoBuf.Reflect.T>}
\r
627 NamespacePrototype.getChildren = function(type) {
\r
628 type = type || null;
\r
630 return this.children.slice();
\r
632 for (var i=0, k=this.children.length; i<k; ++i)
\r
633 if (this.children[i] instanceof type)
\r
634 children.push(this.children[i]);
\r
639 * Adds a child to the namespace.
\r
640 * @param {ProtoBuf.Reflect.T} child Child
\r
641 * @throws {Error} If the child cannot be added (duplicate)
\r
644 NamespacePrototype.addChild = function(child) {
\r
646 if (other = this.getChild(child.name)) {
\r
647 // Try to revert camelcase transformation on collision
\r
648 if (other instanceof Message.Field && other.name !== other.originalName && this.getChild(other.originalName) === null)
\r
649 other.name = other.originalName; // Revert previous first (effectively keeps both originals)
\r
650 else if (child instanceof Message.Field && child.name !== child.originalName && this.getChild(child.originalName) === null)
\r
651 child.name = child.originalName;
\r
653 throw Error("Duplicate name in namespace "+this.toString(true)+": "+child.name);
\r
655 this.children.push(child);
\r
659 * Gets a child by its name or id.
\r
660 * @param {string|number} nameOrId Child name or id
\r
661 * @return {?ProtoBuf.Reflect.T} The child or null if not found
\r
664 NamespacePrototype.getChild = function(nameOrId) {
\r
665 var key = typeof nameOrId === 'number' ? 'id' : 'name';
\r
666 for (var i=0, k=this.children.length; i<k; ++i)
\r
667 if (this.children[i][key] === nameOrId)
\r
668 return this.children[i];
\r
673 * Resolves a reflect object inside of this namespace.
\r
674 * @param {string|!Array.<string>} qn Qualified name to resolve
\r
675 * @param {boolean=} excludeNonNamespace Excludes non-namespace types, defaults to `false`
\r
676 * @return {?ProtoBuf.Reflect.Namespace} The resolved type or null if not found
\r
679 NamespacePrototype.resolve = function(qn, excludeNonNamespace) {
\r
680 var part = typeof qn === 'string' ? qn.split(".") : qn,
\r
683 if (part[i] === "") { // Fully qualified name, e.g. ".My.Message'
\r
684 while (ptr.parent !== null)
\r
691 if (!(ptr instanceof Reflect.Namespace)) {
\r
695 child = ptr.getChild(part[i]);
\r
696 if (!child || !(child instanceof Reflect.T) || (excludeNonNamespace && !(child instanceof Reflect.Namespace))) {
\r
701 } while (i < part.length);
\r
704 // Else search the parent
\r
705 if (this.parent !== null)
\r
706 return this.parent.resolve(qn, excludeNonNamespace);
\r
707 } while (ptr != null);
\r
712 * Determines the shortest qualified name of the specified type, if any, relative to this namespace.
\r
713 * @param {!ProtoBuf.Reflect.T} t Reflection type
\r
714 * @returns {string} The shortest qualified name or, if there is none, the fqn
\r
717 NamespacePrototype.qn = function(t) {
\r
718 var part = [], ptr = t;
\r
720 part.unshift(ptr.name);
\r
722 } while (ptr !== null);
\r
723 for (var len=1; len <= part.length; len++) {
\r
724 var qn = part.slice(part.length-len);
\r
725 if (t === this.resolve(qn, t instanceof Reflect.Namespace))
\r
726 return qn.join(".");
\r
732 * Builds the namespace and returns the runtime counterpart.
\r
733 * @return {Object.<string,Function|Object>} Runtime namespace
\r
736 NamespacePrototype.build = function() {
\r
739 var children = this.children;
\r
740 for (var i=0, k=children.length, child; i<k; ++i) {
\r
741 child = children[i];
\r
742 if (child instanceof Namespace)
\r
743 ns[child.name] = child.build();
\r
745 if (Object.defineProperty)
\r
746 Object.defineProperty(ns, "$options", { "value": this.buildOpt() });
\r
751 * Builds the namespace's '$options' property.
\r
752 * @return {Object.<string,*>}
\r
754 NamespacePrototype.buildOpt = function() {
\r
756 keys = Object.keys(this.options);
\r
757 for (var i=0, k=keys.length; i<k; ++i) {
\r
759 val = this.options[keys[i]];
\r
760 // TODO: Options are not resolved, yet.
\r
761 // if (val instanceof Namespace) {
\r
762 // opt[key] = val.build();
\r
771 * Gets the value assigned to the option with the specified name.
\r
772 * @param {string=} name Returns the option value if specified, otherwise all options are returned.
\r
773 * @return {*|Object.<string,*>}null} Option value or NULL if there is no such option
\r
775 NamespacePrototype.getOption = function(name) {
\r
776 if (typeof name === 'undefined')
\r
777 return this.options;
\r
778 return typeof this.options[name] !== 'undefined' ? this.options[name] : null;
\r
782 * @alias ProtoBuf.Reflect.Namespace
\r
785 Reflect.Namespace = Namespace;
\r
788 * Constructs a new Element implementation that checks and converts values for a
\r
789 * particular field type, as appropriate.
\r
791 * An Element represents a single value: either the value of a singular field,
\r
792 * or a value contained in one entry of a repeated field or map field. This
\r
793 * class does not implement these higher-level concepts; it only encapsulates
\r
794 * the low-level typechecking and conversion.
\r
796 * @exports ProtoBuf.Reflect.Element
\r
797 * @param {{name: string, wireType: number}} type Resolved data type
\r
798 * @param {ProtoBuf.Reflect.T|null} resolvedType Resolved type, if relevant
\r
799 * (e.g. submessage field).
\r
800 * @param {boolean} isMapKey Is this element a Map key? The value will be
\r
801 * converted to string form if so.
\r
802 * @param {string} syntax Syntax level of defining message type, e.g.,
\r
803 * proto2 or proto3.
\r
804 * @param {string} name Name of the field containing this element (for error
\r
808 var Element = function(type, resolvedType, isMapKey, syntax, name) {
\r
811 * Element type, as a string (e.g., int32).
\r
812 * @type {{name: string, wireType: number}}
\r
817 * Element type reference to submessage or enum definition, if needed.
\r
818 * @type {ProtoBuf.Reflect.T|null}
\r
820 this.resolvedType = resolvedType;
\r
823 * Element is a map key.
\r
826 this.isMapKey = isMapKey;
\r
829 * Syntax level of defining message type, e.g., proto2 or proto3.
\r
832 this.syntax = syntax;
\r
835 * Name of the field containing this element (for error messages)
\r
840 if (isMapKey && ProtoBuf.MAP_KEY_TYPES.indexOf(type) < 0)
\r
841 throw Error("Invalid map key type: " + type.name);
\r
844 var ElementPrototype = Element.prototype;
\r
847 * Obtains a (new) default value for the specified type.
\r
848 * @param type {string|{name: string, wireType: number}} Field type
\r
849 * @returns {*} Default value
\r
852 function mkDefault(type) {
\r
853 if (typeof type === 'string')
\r
854 type = ProtoBuf.TYPES[type];
\r
855 if (typeof type.defaultValue === 'undefined')
\r
856 throw Error("default value for type "+type.name+" is not supported");
\r
857 if (type == ProtoBuf.TYPES["bytes"])
\r
858 return new ByteBuffer(0);
\r
859 return type.defaultValue;
\r
863 * Returns the default value for this field in proto3.
\r
865 * @param type {string|{name: string, wireType: number}} the field type
\r
866 * @returns {*} Default value
\r
868 Element.defaultFieldValue = mkDefault;
\r
871 * Makes a Long from a value.
\r
872 * @param {{low: number, high: number, unsigned: boolean}|string|number} value Value
\r
873 * @param {boolean=} unsigned Whether unsigned or not, defaults to reuse it from Long-like objects or to signed for
\r
874 * strings and numbers
\r
876 * @throws {Error} If the value cannot be converted to a Long
\r
879 function mkLong(value, unsigned) {
\r
880 if (value && typeof value.low === 'number' && typeof value.high === 'number' && typeof value.unsigned === 'boolean'
\r
881 && value.low === value.low && value.high === value.high)
\r
882 return new ProtoBuf.Long(value.low, value.high, typeof unsigned === 'undefined' ? value.unsigned : unsigned);
\r
883 if (typeof value === 'string')
\r
884 return ProtoBuf.Long.fromString(value, unsigned || false, 10);
\r
885 if (typeof value === 'number')
\r
886 return ProtoBuf.Long.fromNumber(value, unsigned || false);
\r
887 throw Error("not convertible to Long");
\r
890 ElementPrototype.toString = function() {
\r
891 return (this.name || '') + (this.isMapKey ? 'map' : 'value') + ' element';
\r
895 * Checks if the given value can be set for an element of this type (singular
\r
896 * field or one element of a repeated field or map).
\r
897 * @param {*} value Value to check
\r
898 * @return {*} Verified, maybe adjusted, value
\r
899 * @throws {Error} If the value cannot be verified for this element slot
\r
902 ElementPrototype.verifyValue = function(value) {
\r
904 function fail(val, msg) {
\r
905 throw Error("Illegal value for "+self.toString(true)+" of type "+self.type.name+": "+val+" ("+msg+")");
\r
907 switch (this.type) {
\r
909 case ProtoBuf.TYPES["int32"]:
\r
910 case ProtoBuf.TYPES["sint32"]:
\r
911 case ProtoBuf.TYPES["sfixed32"]:
\r
912 // Account for !NaN: value === value
\r
913 if (typeof value !== 'number' || (value === value && value % 1 !== 0))
\r
914 fail(typeof value, "not an integer");
\r
915 return value > 4294967295 ? value | 0 : value;
\r
918 case ProtoBuf.TYPES["uint32"]:
\r
919 case ProtoBuf.TYPES["fixed32"]:
\r
920 if (typeof value !== 'number' || (value === value && value % 1 !== 0))
\r
921 fail(typeof value, "not an integer");
\r
922 return value < 0 ? value >>> 0 : value;
\r
925 case ProtoBuf.TYPES["int64"]:
\r
926 case ProtoBuf.TYPES["sint64"]:
\r
927 case ProtoBuf.TYPES["sfixed64"]: {
\r
930 return mkLong(value, false);
\r
932 fail(typeof value, e.message);
\r
935 fail(typeof value, "requires Long.js");
\r
939 case ProtoBuf.TYPES["uint64"]:
\r
940 case ProtoBuf.TYPES["fixed64"]: {
\r
943 return mkLong(value, true);
\r
945 fail(typeof value, e.message);
\r
948 fail(typeof value, "requires Long.js");
\r
952 case ProtoBuf.TYPES["bool"]:
\r
953 if (typeof value !== 'boolean')
\r
954 fail(typeof value, "not a boolean");
\r
958 case ProtoBuf.TYPES["float"]:
\r
959 case ProtoBuf.TYPES["double"]:
\r
960 if (typeof value !== 'number')
\r
961 fail(typeof value, "not a number");
\r
964 // Length-delimited string
\r
965 case ProtoBuf.TYPES["string"]:
\r
966 if (typeof value !== 'string' && !(value && value instanceof String))
\r
967 fail(typeof value, "not a string");
\r
968 return ""+value; // Convert String object to string
\r
970 // Length-delimited bytes
\r
971 case ProtoBuf.TYPES["bytes"]:
\r
972 if (ByteBuffer.isByteBuffer(value))
\r
974 return ByteBuffer.wrap(value, "base64");
\r
976 // Constant enum value
\r
977 case ProtoBuf.TYPES["enum"]: {
\r
978 var values = this.resolvedType.getChildren(ProtoBuf.Reflect.Enum.Value);
\r
979 for (i=0; i<values.length; i++)
\r
980 if (values[i].name == value)
\r
981 return values[i].id;
\r
982 else if (values[i].id == value)
\r
983 return values[i].id;
\r
985 if (this.syntax === 'proto3') {
\r
986 // proto3: just make sure it's an integer.
\r
987 if (typeof value !== 'number' || (value === value && value % 1 !== 0))
\r
988 fail(typeof value, "not an integer");
\r
989 if (value > 4294967295 || value < 0)
\r
990 fail(typeof value, "not in range for uint32")
\r
993 // proto2 requires enum values to be valid.
\r
994 fail(value, "not a valid enum value");
\r
997 // Embedded message
\r
998 case ProtoBuf.TYPES["group"]:
\r
999 case ProtoBuf.TYPES["message"]: {
\r
1000 if (!value || typeof value !== 'object')
\r
1001 fail(typeof value, "object expected");
\r
1002 if (value instanceof this.resolvedType.clazz)
\r
1004 if (value instanceof ProtoBuf.Builder.Message) {
\r
1005 // Mismatched type: Convert to object (see: https://github.com/dcodeIO/ProtoBuf.js/issues/180)
\r
1007 for (var i in value)
\r
1008 if (value.hasOwnProperty(i))
\r
1009 obj[i] = value[i];
\r
1012 // Else let's try to construct one from a key-value object
\r
1013 return new (this.resolvedType.clazz)(value); // May throw for a hundred of reasons
\r
1017 // We should never end here
\r
1018 throw Error("[INTERNAL] Illegal value for "+this.toString(true)+": "+value+" (undefined type "+this.type+")");
\r
1022 * Calculates the byte length of an element on the wire.
\r
1023 * @param {number} id Field number
\r
1024 * @param {*} value Field value
\r
1025 * @returns {number} Byte length
\r
1026 * @throws {Error} If the value cannot be calculated
\r
1029 ElementPrototype.calculateLength = function(id, value) {
\r
1030 if (value === null) return 0; // Nothing to encode
\r
1031 // Tag has already been written
\r
1033 switch (this.type) {
\r
1034 case ProtoBuf.TYPES["int32"]:
\r
1035 return value < 0 ? ByteBuffer.calculateVarint64(value) : ByteBuffer.calculateVarint32(value);
\r
1036 case ProtoBuf.TYPES["uint32"]:
\r
1037 return ByteBuffer.calculateVarint32(value);
\r
1038 case ProtoBuf.TYPES["sint32"]:
\r
1039 return ByteBuffer.calculateVarint32(ByteBuffer.zigZagEncode32(value));
\r
1040 case ProtoBuf.TYPES["fixed32"]:
\r
1041 case ProtoBuf.TYPES["sfixed32"]:
\r
1042 case ProtoBuf.TYPES["float"]:
\r
1044 case ProtoBuf.TYPES["int64"]:
\r
1045 case ProtoBuf.TYPES["uint64"]:
\r
1046 return ByteBuffer.calculateVarint64(value);
\r
1047 case ProtoBuf.TYPES["sint64"]:
\r
1048 return ByteBuffer.calculateVarint64(ByteBuffer.zigZagEncode64(value));
\r
1049 case ProtoBuf.TYPES["fixed64"]:
\r
1050 case ProtoBuf.TYPES["sfixed64"]:
\r
1052 case ProtoBuf.TYPES["bool"]:
\r
1054 case ProtoBuf.TYPES["enum"]:
\r
1055 return ByteBuffer.calculateVarint32(value);
\r
1056 case ProtoBuf.TYPES["double"]:
\r
1058 case ProtoBuf.TYPES["string"]:
\r
1059 n = ByteBuffer.calculateUTF8Bytes(value);
\r
1060 return ByteBuffer.calculateVarint32(n) + n;
\r
1061 case ProtoBuf.TYPES["bytes"]:
\r
1062 if (value.remaining() < 0)
\r
1063 throw Error("Illegal value for "+this.toString(true)+": "+value.remaining()+" bytes remaining");
\r
1064 return ByteBuffer.calculateVarint32(value.remaining()) + value.remaining();
\r
1065 case ProtoBuf.TYPES["message"]:
\r
1066 n = this.resolvedType.calculate(value);
\r
1067 return ByteBuffer.calculateVarint32(n) + n;
\r
1068 case ProtoBuf.TYPES["group"]:
\r
1069 n = this.resolvedType.calculate(value);
\r
1070 return n + ByteBuffer.calculateVarint32((id << 3) | ProtoBuf.WIRE_TYPES.ENDGROUP);
\r
1072 // We should never end here
\r
1073 throw Error("[INTERNAL] Illegal value to encode in "+this.toString(true)+": "+value+" (unknown type)");
\r
1077 * Encodes a value to the specified buffer. Does not encode the key.
\r
1078 * @param {number} id Field number
\r
1079 * @param {*} value Field value
\r
1080 * @param {ByteBuffer} buffer ByteBuffer to encode to
\r
1081 * @return {ByteBuffer} The ByteBuffer for chaining
\r
1082 * @throws {Error} If the value cannot be encoded
\r
1085 ElementPrototype.encodeValue = function(id, value, buffer) {
\r
1086 if (value === null) return buffer; // Nothing to encode
\r
1087 // Tag has already been written
\r
1089 switch (this.type) {
\r
1090 // 32bit signed varint
\r
1091 case ProtoBuf.TYPES["int32"]:
\r
1092 // "If you use int32 or int64 as the type for a negative number, the resulting varint is always ten bytes
\r
1093 // long – it is, effectively, treated like a very large unsigned integer." (see #122)
\r
1095 buffer.writeVarint64(value);
\r
1097 buffer.writeVarint32(value);
\r
1100 // 32bit unsigned varint
\r
1101 case ProtoBuf.TYPES["uint32"]:
\r
1102 buffer.writeVarint32(value);
\r
1105 // 32bit varint zig-zag
\r
1106 case ProtoBuf.TYPES["sint32"]:
\r
1107 buffer.writeVarint32ZigZag(value);
\r
1110 // Fixed unsigned 32bit
\r
1111 case ProtoBuf.TYPES["fixed32"]:
\r
1112 buffer.writeUint32(value);
\r
1115 // Fixed signed 32bit
\r
1116 case ProtoBuf.TYPES["sfixed32"]:
\r
1117 buffer.writeInt32(value);
\r
1120 // 64bit varint as-is
\r
1121 case ProtoBuf.TYPES["int64"]:
\r
1122 case ProtoBuf.TYPES["uint64"]:
\r
1123 buffer.writeVarint64(value); // throws
\r
1126 // 64bit varint zig-zag
\r
1127 case ProtoBuf.TYPES["sint64"]:
\r
1128 buffer.writeVarint64ZigZag(value); // throws
\r
1131 // Fixed unsigned 64bit
\r
1132 case ProtoBuf.TYPES["fixed64"]:
\r
1133 buffer.writeUint64(value); // throws
\r
1136 // Fixed signed 64bit
\r
1137 case ProtoBuf.TYPES["sfixed64"]:
\r
1138 buffer.writeInt64(value); // throws
\r
1142 case ProtoBuf.TYPES["bool"]:
\r
1143 if (typeof value === 'string')
\r
1144 buffer.writeVarint32(value.toLowerCase() === 'false' ? 0 : !!value);
\r
1146 buffer.writeVarint32(value ? 1 : 0);
\r
1149 // Constant enum value
\r
1150 case ProtoBuf.TYPES["enum"]:
\r
1151 buffer.writeVarint32(value);
\r
1155 case ProtoBuf.TYPES["float"]:
\r
1156 buffer.writeFloat32(value);
\r
1160 case ProtoBuf.TYPES["double"]:
\r
1161 buffer.writeFloat64(value);
\r
1164 // Length-delimited string
\r
1165 case ProtoBuf.TYPES["string"]:
\r
1166 buffer.writeVString(value);
\r
1169 // Length-delimited bytes
\r
1170 case ProtoBuf.TYPES["bytes"]:
\r
1171 if (value.remaining() < 0)
\r
1172 throw Error("Illegal value for "+this.toString(true)+": "+value.remaining()+" bytes remaining");
\r
1173 var prevOffset = value.offset;
\r
1174 buffer.writeVarint32(value.remaining());
\r
1175 buffer.append(value);
\r
1176 value.offset = prevOffset;
\r
1179 // Embedded message
\r
1180 case ProtoBuf.TYPES["message"]:
\r
1181 var bb = new ByteBuffer().LE();
\r
1182 this.resolvedType.encode(value, bb);
\r
1183 buffer.writeVarint32(bb.offset);
\r
1184 buffer.append(bb.flip());
\r
1188 case ProtoBuf.TYPES["group"]:
\r
1189 this.resolvedType.encode(value, buffer);
\r
1190 buffer.writeVarint32((id << 3) | ProtoBuf.WIRE_TYPES.ENDGROUP);
\r
1194 // We should never end here
\r
1195 throw Error("[INTERNAL] Illegal value to encode in "+this.toString(true)+": "+value+" (unknown type)");
\r
1201 * Decode one element value from the specified buffer.
\r
1202 * @param {ByteBuffer} buffer ByteBuffer to decode from
\r
1203 * @param {number} wireType The field wire type
\r
1204 * @param {number} id The field number
\r
1205 * @return {*} Decoded value
\r
1206 * @throws {Error} If the field cannot be decoded
\r
1209 ElementPrototype.decode = function(buffer, wireType, id) {
\r
1210 if (wireType != this.type.wireType)
\r
1211 throw Error("Unexpected wire type for element");
\r
1213 var value, nBytes;
\r
1214 switch (this.type) {
\r
1215 // 32bit signed varint
\r
1216 case ProtoBuf.TYPES["int32"]:
\r
1217 return buffer.readVarint32() | 0;
\r
1219 // 32bit unsigned varint
\r
1220 case ProtoBuf.TYPES["uint32"]:
\r
1221 return buffer.readVarint32() >>> 0;
\r
1223 // 32bit signed varint zig-zag
\r
1224 case ProtoBuf.TYPES["sint32"]:
\r
1225 return buffer.readVarint32ZigZag() | 0;
\r
1227 // Fixed 32bit unsigned
\r
1228 case ProtoBuf.TYPES["fixed32"]:
\r
1229 return buffer.readUint32() >>> 0;
\r
1231 case ProtoBuf.TYPES["sfixed32"]:
\r
1232 return buffer.readInt32() | 0;
\r
1234 // 64bit signed varint
\r
1235 case ProtoBuf.TYPES["int64"]:
\r
1236 return buffer.readVarint64();
\r
1238 // 64bit unsigned varint
\r
1239 case ProtoBuf.TYPES["uint64"]:
\r
1240 return buffer.readVarint64().toUnsigned();
\r
1242 // 64bit signed varint zig-zag
\r
1243 case ProtoBuf.TYPES["sint64"]:
\r
1244 return buffer.readVarint64ZigZag();
\r
1246 // Fixed 64bit unsigned
\r
1247 case ProtoBuf.TYPES["fixed64"]:
\r
1248 return buffer.readUint64();
\r
1250 // Fixed 64bit signed
\r
1251 case ProtoBuf.TYPES["sfixed64"]:
\r
1252 return buffer.readInt64();
\r
1255 case ProtoBuf.TYPES["bool"]:
\r
1256 return !!buffer.readVarint32();
\r
1258 // Constant enum value (varint)
\r
1259 case ProtoBuf.TYPES["enum"]:
\r
1260 // The following Builder.Message#set will already throw
\r
1261 return buffer.readVarint32();
\r
1264 case ProtoBuf.TYPES["float"]:
\r
1265 return buffer.readFloat();
\r
1268 case ProtoBuf.TYPES["double"]:
\r
1269 return buffer.readDouble();
\r
1271 // Length-delimited string
\r
1272 case ProtoBuf.TYPES["string"]:
\r
1273 return buffer.readVString();
\r
1275 // Length-delimited bytes
\r
1276 case ProtoBuf.TYPES["bytes"]: {
\r
1277 nBytes = buffer.readVarint32();
\r
1278 if (buffer.remaining() < nBytes)
\r
1279 throw Error("Illegal number of bytes for "+this.toString(true)+": "+nBytes+" required but got only "+buffer.remaining());
\r
1280 value = buffer.clone(); // Offset already set
\r
1281 value.limit = value.offset+nBytes;
\r
1282 buffer.offset += nBytes;
\r
1286 // Length-delimited embedded message
\r
1287 case ProtoBuf.TYPES["message"]: {
\r
1288 nBytes = buffer.readVarint32();
\r
1289 return this.resolvedType.decode(buffer, nBytes);
\r
1293 case ProtoBuf.TYPES["group"]:
\r
1294 return this.resolvedType.decode(buffer, -1, id);
\r
1297 // We should never end here
\r
1298 throw Error("[INTERNAL] Illegal decode type");
\r
1302 * Converts a value from a string to the canonical element type.
\r
1304 * Legal only when isMapKey is true.
\r
1306 * @param {string} str The string value
\r
1307 * @returns {*} The value
\r
1309 ElementPrototype.valueFromString = function(str) {
\r
1310 if (!this.isMapKey) {
\r
1311 throw Error("valueFromString() called on non-map-key element");
\r
1314 switch (this.type) {
\r
1315 case ProtoBuf.TYPES["int32"]:
\r
1316 case ProtoBuf.TYPES["sint32"]:
\r
1317 case ProtoBuf.TYPES["sfixed32"]:
\r
1318 case ProtoBuf.TYPES["uint32"]:
\r
1319 case ProtoBuf.TYPES["fixed32"]:
\r
1320 return this.verifyValue(parseInt(str));
\r
1322 case ProtoBuf.TYPES["int64"]:
\r
1323 case ProtoBuf.TYPES["sint64"]:
\r
1324 case ProtoBuf.TYPES["sfixed64"]:
\r
1325 case ProtoBuf.TYPES["uint64"]:
\r
1326 case ProtoBuf.TYPES["fixed64"]:
\r
1327 // Long-based fields support conversions from string already.
\r
1328 return this.verifyValue(str);
\r
1330 case ProtoBuf.TYPES["bool"]:
\r
1331 return str === "true";
\r
1333 case ProtoBuf.TYPES["string"]:
\r
1334 return this.verifyValue(str);
\r
1336 case ProtoBuf.TYPES["bytes"]:
\r
1337 return ByteBuffer.fromBinary(str);
\r
1342 * Converts a value from the canonical element type to a string.
\r
1344 * It should be the case that `valueFromString(valueToString(val))` returns
\r
1345 * a value equivalent to `verifyValue(val)` for every legal value of `val`
\r
1346 * according to this element type.
\r
1348 * This may be used when the element must be stored or used as a string,
\r
1349 * e.g., as a map key on an Object.
\r
1351 * Legal only when isMapKey is true.
\r
1353 * @param {*} val The value
\r
1354 * @returns {string} The string form of the value.
\r
1356 ElementPrototype.valueToString = function(value) {
\r
1357 if (!this.isMapKey) {
\r
1358 throw Error("valueToString() called on non-map-key element");
\r
1361 if (this.type === ProtoBuf.TYPES["bytes"]) {
\r
1362 return value.toString("binary");
\r
1364 return value.toString();
\r
1369 * @alias ProtoBuf.Reflect.Element
\r
1372 Reflect.Element = Element;
\r
1375 * Constructs a new Message.
\r
1376 * @exports ProtoBuf.Reflect.Message
\r
1377 * @param {!ProtoBuf.Builder} builder Builder reference
\r
1378 * @param {!ProtoBuf.Reflect.Namespace} parent Parent message or namespace
\r
1379 * @param {string} name Message name
\r
1380 * @param {Object.<string,*>=} options Message options
\r
1381 * @param {boolean=} isGroup `true` if this is a legacy group
\r
1382 * @param {string?} syntax The syntax level of this definition (e.g., proto3)
\r
1384 * @extends ProtoBuf.Reflect.Namespace
\r
1386 var Message = function(builder, parent, name, options, isGroup, syntax) {
\r
1387 Namespace.call(this, builder, parent, name, options, syntax);
\r
1392 this.className = "Message";
\r
1395 * Extensions range.
\r
1396 * @type {!Array.<number>|undefined}
\r
1399 this.extensions = undefined;
\r
1402 * Runtime message class.
\r
1403 * @type {?function(new:ProtoBuf.Builder.Message)}
\r
1406 this.clazz = null;
\r
1409 * Whether this is a legacy group or not.
\r
1413 this.isGroup = !!isGroup;
\r
1415 // The following cached collections are used to efficiently iterate over or look up fields when decoding.
\r
1419 * @type {?Array.<!ProtoBuf.Reflect.Message.Field>}
\r
1422 this._fields = null;
\r
1425 * Cached fields by id.
\r
1426 * @type {?Object.<number,!ProtoBuf.Reflect.Message.Field>}
\r
1429 this._fieldsById = null;
\r
1432 * Cached fields by name.
\r
1433 * @type {?Object.<string,!ProtoBuf.Reflect.Message.Field>}
\r
1436 this._fieldsByName = null;
\r
1440 * @alias ProtoBuf.Reflect.Message.prototype
\r
1443 var MessagePrototype = Message.prototype = Object.create(Namespace.prototype);
\r
1446 * Builds the message and returns the runtime counterpart, which is a fully functional class.
\r
1447 * @see ProtoBuf.Builder.Message
\r
1448 * @param {boolean=} rebuild Whether to rebuild or not, defaults to false
\r
1449 * @return {ProtoBuf.Reflect.Message} Message class
\r
1450 * @throws {Error} If the message cannot be built
\r
1453 MessagePrototype.build = function(rebuild) {
\r
1454 if (this.clazz && !rebuild)
\r
1455 return this.clazz;
\r
1457 // Create the runtime Message class in its own scope
\r
1458 var clazz = (function(ProtoBuf, T) {
\r
1460 var fields = T.getChildren(ProtoBuf.Reflect.Message.Field),
\r
1461 oneofs = T.getChildren(ProtoBuf.Reflect.Message.OneOf);
\r
1464 * Constructs a new runtime Message.
\r
1465 * @name ProtoBuf.Builder.Message
\r
1466 * @class Barebone of all runtime messages.
\r
1467 * @param {!Object.<string,*>|string} values Preset values
\r
1468 * @param {...string} var_args
\r
1470 * @throws {Error} If the message cannot be created
\r
1472 var Message = function(values, var_args) {
\r
1473 ProtoBuf.Builder.Message.call(this);
\r
1475 // Create virtual oneof properties
\r
1476 for (var i=0, k=oneofs.length; i<k; ++i)
\r
1477 this[oneofs[i].name] = null;
\r
1478 // Create fields and set default values
\r
1479 for (i=0, k=fields.length; i<k; ++i) {
\r
1480 var field = fields[i];
\r
1481 this[field.name] =
\r
1482 field.repeated ? [] :
\r
1483 (field.map ? new ProtoBuf.Map(field) : null);
\r
1484 if ((field.required || T.syntax === 'proto3') &&
\r
1485 field.defaultValue !== null)
\r
1486 this[field.name] = field.defaultValue;
\r
1489 if (arguments.length > 0) {
\r
1491 // Set field values from a values object
\r
1492 if (arguments.length === 1 && values !== null && typeof values === 'object' &&
\r
1493 /* not _another_ Message */ (typeof values.encode !== 'function' || values instanceof Message) &&
\r
1494 /* not a repeated field */ !Array.isArray(values) &&
\r
1495 /* not a Map */ !(values instanceof ProtoBuf.Map) &&
\r
1496 /* not a ByteBuffer */ !ByteBuffer.isByteBuffer(values) &&
\r
1497 /* not an ArrayBuffer */ !(values instanceof ArrayBuffer) &&
\r
1498 /* not a Long */ !(ProtoBuf.Long && values instanceof ProtoBuf.Long)) {
\r
1499 this.$set(values);
\r
1500 } else // Set field values from arguments, in declaration order
\r
1501 for (i=0, k=arguments.length; i<k; ++i)
\r
1502 if (typeof (value = arguments[i]) !== 'undefined')
\r
1503 this.$set(fields[i].name, value); // May throw
\r
1508 * @alias ProtoBuf.Builder.Message.prototype
\r
1511 var MessagePrototype = Message.prototype = Object.create(ProtoBuf.Builder.Message.prototype);
\r
1514 * Adds a value to a repeated field.
\r
1515 * @name ProtoBuf.Builder.Message#add
\r
1517 * @param {string} key Field name
\r
1518 * @param {*} value Value to add
\r
1519 * @param {boolean=} noAssert Whether to assert the value or not (asserts by default)
\r
1520 * @returns {!ProtoBuf.Builder.Message} this
\r
1521 * @throws {Error} If the value cannot be added
\r
1524 MessagePrototype.add = function(key, value, noAssert) {
\r
1525 var field = T._fieldsByName[key];
\r
1528 throw Error(this+"#"+key+" is undefined");
\r
1529 if (!(field instanceof ProtoBuf.Reflect.Message.Field))
\r
1530 throw Error(this+"#"+key+" is not a field: "+field.toString(true)); // May throw if it's an enum or embedded message
\r
1531 if (!field.repeated)
\r
1532 throw Error(this+"#"+key+" is not a repeated field");
\r
1533 value = field.verifyValue(value, true);
\r
1535 if (this[key] === null)
\r
1537 this[key].push(value);
\r
1542 * Adds a value to a repeated field. This is an alias for {@link ProtoBuf.Builder.Message#add}.
\r
1543 * @name ProtoBuf.Builder.Message#$add
\r
1545 * @param {string} key Field name
\r
1546 * @param {*} value Value to add
\r
1547 * @param {boolean=} noAssert Whether to assert the value or not (asserts by default)
\r
1548 * @returns {!ProtoBuf.Builder.Message} this
\r
1549 * @throws {Error} If the value cannot be added
\r
1552 MessagePrototype.$add = MessagePrototype.add;
\r
1555 * Sets a field's value.
\r
1556 * @name ProtoBuf.Builder.Message#set
\r
1558 * @param {string|!Object.<string,*>} keyOrObj String key or plain object holding multiple values
\r
1559 * @param {(*|boolean)=} value Value to set if key is a string, otherwise omitted
\r
1560 * @param {boolean=} noAssert Whether to not assert for an actual field / proper value type, defaults to `false`
\r
1561 * @returns {!ProtoBuf.Builder.Message} this
\r
1562 * @throws {Error} If the value cannot be set
\r
1565 MessagePrototype.set = function(keyOrObj, value, noAssert) {
\r
1566 if (keyOrObj && typeof keyOrObj === 'object') {
\r
1568 for (var ikey in keyOrObj) {
\r
1569 // Check if virtual oneof field - don't set these
\r
1570 if (keyOrObj.hasOwnProperty(ikey) && typeof (value = keyOrObj[ikey]) !== 'undefined' && T._oneofsByName[ikey] === undefined)
\r
1571 this.$set(ikey, value, noAssert);
\r
1575 var field = T._fieldsByName[keyOrObj];
\r
1578 throw Error(this+"#"+keyOrObj+" is not a field: undefined");
\r
1579 if (!(field instanceof ProtoBuf.Reflect.Message.Field))
\r
1580 throw Error(this+"#"+keyOrObj+" is not a field: "+field.toString(true));
\r
1581 this[field.name] = (value = field.verifyValue(value)); // May throw
\r
1583 this[keyOrObj] = value;
\r
1584 if (field && field.oneof) { // Field is part of an OneOf (not a virtual OneOf field)
\r
1585 var currentField = this[field.oneof.name]; // Virtual field references currently set field
\r
1586 if (value !== null) {
\r
1587 if (currentField !== null && currentField !== field.name)
\r
1588 this[currentField] = null; // Clear currently set field
\r
1589 this[field.oneof.name] = field.name; // Point virtual field at this field
\r
1590 } else if (/* value === null && */currentField === keyOrObj)
\r
1591 this[field.oneof.name] = null; // Clear virtual field (current field explicitly cleared)
\r
1597 * Sets a field's value. This is an alias for [@link ProtoBuf.Builder.Message#set}.
\r
1598 * @name ProtoBuf.Builder.Message#$set
\r
1600 * @param {string|!Object.<string,*>} keyOrObj String key or plain object holding multiple values
\r
1601 * @param {(*|boolean)=} value Value to set if key is a string, otherwise omitted
\r
1602 * @param {boolean=} noAssert Whether to not assert the value, defaults to `false`
\r
1603 * @throws {Error} If the value cannot be set
\r
1606 MessagePrototype.$set = MessagePrototype.set;
\r
1609 * Gets a field's value.
\r
1610 * @name ProtoBuf.Builder.Message#get
\r
1612 * @param {string} key Key
\r
1613 * @param {boolean=} noAssert Whether to not assert for an actual field, defaults to `false`
\r
1614 * @return {*} Value
\r
1615 * @throws {Error} If there is no such field
\r
1618 MessagePrototype.get = function(key, noAssert) {
\r
1621 var field = T._fieldsByName[key];
\r
1622 if (!field || !(field instanceof ProtoBuf.Reflect.Message.Field))
\r
1623 throw Error(this+"#"+key+" is not a field: undefined");
\r
1624 if (!(field instanceof ProtoBuf.Reflect.Message.Field))
\r
1625 throw Error(this+"#"+key+" is not a field: "+field.toString(true));
\r
1626 return this[field.name];
\r
1630 * Gets a field's value. This is an alias for {@link ProtoBuf.Builder.Message#$get}.
\r
1631 * @name ProtoBuf.Builder.Message#$get
\r
1633 * @param {string} key Key
\r
1634 * @return {*} Value
\r
1635 * @throws {Error} If there is no such field
\r
1638 MessagePrototype.$get = MessagePrototype.get;
\r
1640 // Getters and setters
\r
1642 for (var i=0; i<fields.length; i++) {
\r
1643 var field = fields[i];
\r
1644 // no setters for extension fields as these are named by their fqn
\r
1645 if (field instanceof ProtoBuf.Reflect.Message.ExtensionField)
\r
1648 if (T.builder.options['populateAccessors'])
\r
1649 (function(field) {
\r
1650 // set/get[SomeValue]
\r
1651 var Name = field.originalName.replace(/(_[a-zA-Z])/g, function(match) {
\r
1652 return match.toUpperCase().replace('_','');
\r
1654 Name = Name.substring(0,1).toUpperCase() + Name.substring(1);
\r
1656 // set/get_[some_value] FIXME: Do we really need these?
\r
1657 var name = field.originalName.replace(/([A-Z])/g, function(match) {
\r
1662 * The current field's unbound setter function.
\r
1664 * @param {*} value
\r
1665 * @param {boolean=} noAssert
\r
1666 * @returns {!ProtoBuf.Builder.Message}
\r
1669 var setter = function(value, noAssert) {
\r
1670 this[field.name] = noAssert ? value : field.verifyValue(value);
\r
1675 * The current field's unbound getter function.
\r
1680 var getter = function() {
\r
1681 return this[field.name];
\r
1684 if (T.getChild("set"+Name) === null)
\r
1686 * Sets a value. This method is present for each field, but only if there is no name conflict with
\r
1688 * @name ProtoBuf.Builder.Message#set[SomeField]
\r
1690 * @param {*} value Value to set
\r
1691 * @param {boolean=} noAssert Whether to not assert the value, defaults to `false`
\r
1692 * @returns {!ProtoBuf.Builder.Message} this
\r
1694 * @throws {Error} If the value cannot be set
\r
1696 MessagePrototype["set"+Name] = setter;
\r
1698 if (T.getChild("set_"+name) === null)
\r
1700 * Sets a value. This method is present for each field, but only if there is no name conflict with
\r
1702 * @name ProtoBuf.Builder.Message#set_[some_field]
\r
1704 * @param {*} value Value to set
\r
1705 * @param {boolean=} noAssert Whether to not assert the value, defaults to `false`
\r
1706 * @returns {!ProtoBuf.Builder.Message} this
\r
1708 * @throws {Error} If the value cannot be set
\r
1710 MessagePrototype["set_"+name] = setter;
\r
1712 if (T.getChild("get"+Name) === null)
\r
1714 * Gets a value. This method is present for each field, but only if there is no name conflict with
\r
1716 * @name ProtoBuf.Builder.Message#get[SomeField]
\r
1719 * @return {*} The value
\r
1721 MessagePrototype["get"+Name] = getter;
\r
1723 if (T.getChild("get_"+name) === null)
\r
1725 * Gets a value. This method is present for each field, but only if there is no name conflict with
\r
1727 * @name ProtoBuf.Builder.Message#get_[some_field]
\r
1729 * @return {*} The value
\r
1732 MessagePrototype["get_"+name] = getter;
\r
1740 * Encodes the message.
\r
1741 * @name ProtoBuf.Builder.Message#$encode
\r
1743 * @param {(!ByteBuffer|boolean)=} buffer ByteBuffer to encode to. Will create a new one and flip it if omitted.
\r
1744 * @param {boolean=} noVerify Whether to not verify field values, defaults to `false`
\r
1745 * @return {!ByteBuffer} Encoded message as a ByteBuffer
\r
1746 * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
\r
1747 * returns the encoded ByteBuffer in the `encoded` property on the error.
\r
1749 * @see ProtoBuf.Builder.Message#encode64
\r
1750 * @see ProtoBuf.Builder.Message#encodeHex
\r
1751 * @see ProtoBuf.Builder.Message#encodeAB
\r
1753 MessagePrototype.encode = function(buffer, noVerify) {
\r
1754 if (typeof buffer === 'boolean')
\r
1755 noVerify = buffer,
\r
1756 buffer = undefined;
\r
1757 var isNew = false;
\r
1759 buffer = new ByteBuffer(),
\r
1761 var le = buffer.littleEndian;
\r
1763 T.encode(this, buffer.LE(), noVerify);
\r
1764 return (isNew ? buffer.flip() : buffer).LE(le);
\r
1772 * Encodes a message using the specified data payload.
\r
1773 * @param {!Object.<string,*>} data Data payload
\r
1774 * @param {(!ByteBuffer|boolean)=} buffer ByteBuffer to encode to. Will create a new one and flip it if omitted.
\r
1775 * @param {boolean=} noVerify Whether to not verify field values, defaults to `false`
\r
1776 * @return {!ByteBuffer} Encoded message as a ByteBuffer
\r
1779 Message.encode = function(data, buffer, noVerify) {
\r
1780 return new Message(data).encode(buffer, noVerify);
\r
1784 * Calculates the byte length of the message.
\r
1785 * @name ProtoBuf.Builder.Message#calculate
\r
1787 * @returns {number} Byte length
\r
1788 * @throws {Error} If the message cannot be calculated or if required fields are missing.
\r
1791 MessagePrototype.calculate = function() {
\r
1792 return T.calculate(this);
\r
1796 * Encodes the varint32 length-delimited message.
\r
1797 * @name ProtoBuf.Builder.Message#encodeDelimited
\r
1799 * @param {(!ByteBuffer|boolean)=} buffer ByteBuffer to encode to. Will create a new one and flip it if omitted.
\r
1800 * @param {boolean=} noVerify Whether to not verify field values, defaults to `false`
\r
1801 * @return {!ByteBuffer} Encoded message as a ByteBuffer
\r
1802 * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
\r
1803 * returns the encoded ByteBuffer in the `encoded` property on the error.
\r
1806 MessagePrototype.encodeDelimited = function(buffer, noVerify) {
\r
1807 var isNew = false;
\r
1809 buffer = new ByteBuffer(),
\r
1811 var enc = new ByteBuffer().LE();
\r
1812 T.encode(this, enc, noVerify).flip();
\r
1813 buffer.writeVarint32(enc.remaining());
\r
1814 buffer.append(enc);
\r
1815 return isNew ? buffer.flip() : buffer;
\r
1819 * Directly encodes the message to an ArrayBuffer.
\r
1820 * @name ProtoBuf.Builder.Message#encodeAB
\r
1822 * @return {ArrayBuffer} Encoded message as ArrayBuffer
\r
1823 * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
\r
1824 * returns the encoded ArrayBuffer in the `encoded` property on the error.
\r
1827 MessagePrototype.encodeAB = function() {
\r
1829 return this.encode().toArrayBuffer();
\r
1831 if (e["encoded"]) e["encoded"] = e["encoded"].toArrayBuffer();
\r
1837 * Returns the message as an ArrayBuffer. This is an alias for {@link ProtoBuf.Builder.Message#encodeAB}.
\r
1838 * @name ProtoBuf.Builder.Message#toArrayBuffer
\r
1840 * @return {ArrayBuffer} Encoded message as ArrayBuffer
\r
1841 * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
\r
1842 * returns the encoded ArrayBuffer in the `encoded` property on the error.
\r
1845 MessagePrototype.toArrayBuffer = MessagePrototype.encodeAB;
\r
1848 * Directly encodes the message to a node Buffer.
\r
1849 * @name ProtoBuf.Builder.Message#encodeNB
\r
1851 * @return {!Buffer}
\r
1852 * @throws {Error} If the message cannot be encoded, not running under node.js or if required fields are
\r
1853 * missing. The later still returns the encoded node Buffer in the `encoded` property on the error.
\r
1856 MessagePrototype.encodeNB = function() {
\r
1858 return this.encode().toBuffer();
\r
1860 if (e["encoded"]) e["encoded"] = e["encoded"].toBuffer();
\r
1866 * Returns the message as a node Buffer. This is an alias for {@link ProtoBuf.Builder.Message#encodeNB}.
\r
1867 * @name ProtoBuf.Builder.Message#toBuffer
\r
1869 * @return {!Buffer}
\r
1870 * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
\r
1871 * returns the encoded node Buffer in the `encoded` property on the error.
\r
1874 MessagePrototype.toBuffer = MessagePrototype.encodeNB;
\r
1877 * Directly encodes the message to a base64 encoded string.
\r
1878 * @name ProtoBuf.Builder.Message#encode64
\r
1880 * @return {string} Base64 encoded string
\r
1881 * @throws {Error} If the underlying buffer cannot be encoded or if required fields are missing. The later
\r
1882 * still returns the encoded base64 string in the `encoded` property on the error.
\r
1885 MessagePrototype.encode64 = function() {
\r
1887 return this.encode().toBase64();
\r
1889 if (e["encoded"]) e["encoded"] = e["encoded"].toBase64();
\r
1895 * Returns the message as a base64 encoded string. This is an alias for {@link ProtoBuf.Builder.Message#encode64}.
\r
1896 * @name ProtoBuf.Builder.Message#toBase64
\r
1898 * @return {string} Base64 encoded string
\r
1899 * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
\r
1900 * returns the encoded base64 string in the `encoded` property on the error.
\r
1903 MessagePrototype.toBase64 = MessagePrototype.encode64;
\r
1906 * Directly encodes the message to a hex encoded string.
\r
1907 * @name ProtoBuf.Builder.Message#encodeHex
\r
1909 * @return {string} Hex encoded string
\r
1910 * @throws {Error} If the underlying buffer cannot be encoded or if required fields are missing. The later
\r
1911 * still returns the encoded hex string in the `encoded` property on the error.
\r
1914 MessagePrototype.encodeHex = function() {
\r
1916 return this.encode().toHex();
\r
1918 if (e["encoded"]) e["encoded"] = e["encoded"].toHex();
\r
1924 * Returns the message as a hex encoded string. This is an alias for {@link ProtoBuf.Builder.Message#encodeHex}.
\r
1925 * @name ProtoBuf.Builder.Message#toHex
\r
1927 * @return {string} Hex encoded string
\r
1928 * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
\r
1929 * returns the encoded hex string in the `encoded` property on the error.
\r
1932 MessagePrototype.toHex = MessagePrototype.encodeHex;
\r
1935 * Clones a message object or field value to a raw object.
\r
1936 * @param {*} obj Object to clone
\r
1937 * @param {boolean} binaryAsBase64 Whether to include binary data as base64 strings or as a buffer otherwise
\r
1938 * @param {boolean} longsAsStrings Whether to encode longs as strings
\r
1939 * @param {!ProtoBuf.Reflect.T=} resolvedType The resolved field type if a field
\r
1940 * @returns {*} Cloned object
\r
1943 function cloneRaw(obj, binaryAsBase64, longsAsStrings, resolvedType) {
\r
1944 if (obj === null || typeof obj !== 'object') {
\r
1945 // Convert enum values to their respective names
\r
1946 if (resolvedType && resolvedType instanceof ProtoBuf.Reflect.Enum) {
\r
1947 var name = ProtoBuf.Reflect.Enum.getName(resolvedType.object, obj);
\r
1948 if (name !== null)
\r
1951 // Pass-through string, number, boolean, null...
\r
1954 // Convert ByteBuffers to raw buffer or strings
\r
1955 if (ByteBuffer.isByteBuffer(obj))
\r
1956 return binaryAsBase64 ? obj.toBase64() : obj.toBuffer();
\r
1957 // Convert Longs to proper objects or strings
\r
1958 if (ProtoBuf.Long.isLong(obj))
\r
1959 return longsAsStrings ? obj.toString() : ProtoBuf.Long.fromValue(obj);
\r
1962 if (Array.isArray(obj)) {
\r
1964 obj.forEach(function(v, k) {
\r
1965 clone[k] = cloneRaw(v, binaryAsBase64, longsAsStrings, resolvedType);
\r
1970 // Convert maps to objects
\r
1971 if (obj instanceof ProtoBuf.Map) {
\r
1972 var it = obj.entries();
\r
1973 for (var e = it.next(); !e.done; e = it.next())
\r
1974 clone[obj.keyElem.valueToString(e.value[0])] = cloneRaw(e.value[1], binaryAsBase64, longsAsStrings, obj.valueElem.resolvedType);
\r
1977 // Everything else is a non-null object
\r
1978 var type = obj.$type,
\r
1979 field = undefined;
\r
1980 for (var i in obj)
\r
1981 if (obj.hasOwnProperty(i)) {
\r
1982 if (type && (field = type.getChild(i)))
\r
1983 clone[i] = cloneRaw(obj[i], binaryAsBase64, longsAsStrings, field.resolvedType);
\r
1985 clone[i] = cloneRaw(obj[i], binaryAsBase64, longsAsStrings);
\r
1991 * Returns the message's raw payload.
\r
1992 * @param {boolean=} binaryAsBase64 Whether to include binary data as base64 strings instead of Buffers, defaults to `false`
\r
1993 * @param {boolean} longsAsStrings Whether to encode longs as strings
\r
1994 * @returns {Object.<string,*>} Raw payload
\r
1997 MessagePrototype.toRaw = function(binaryAsBase64, longsAsStrings) {
\r
1998 return cloneRaw(this, !!binaryAsBase64, !!longsAsStrings, this.$type);
\r
2002 * Encodes a message to JSON.
\r
2003 * @returns {string} JSON string
\r
2006 MessagePrototype.encodeJSON = function() {
\r
2007 return JSON.stringify(
\r
2009 /* binary-as-base64 */ true,
\r
2010 /* longs-as-strings */ true,
\r
2017 * Decodes a message from the specified buffer or string.
\r
2018 * @name ProtoBuf.Builder.Message.decode
\r
2020 * @param {!ByteBuffer|!ArrayBuffer|!Buffer|string} buffer Buffer to decode from
\r
2021 * @param {(number|string)=} length Message length. Defaults to decode all the remainig data.
\r
2022 * @param {string=} enc Encoding if buffer is a string: hex, utf8 (not recommended), defaults to base64
\r
2023 * @return {!ProtoBuf.Builder.Message} Decoded message
\r
2024 * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still
\r
2025 * returns the decoded message with missing fields in the `decoded` property on the error.
\r
2027 * @see ProtoBuf.Builder.Message.decode64
\r
2028 * @see ProtoBuf.Builder.Message.decodeHex
\r
2030 Message.decode = function(buffer, length, enc) {
\r
2031 if (typeof length === 'string')
\r
2034 if (typeof buffer === 'string')
\r
2035 buffer = ByteBuffer.wrap(buffer, enc ? enc : "base64");
\r
2036 else if (!ByteBuffer.isByteBuffer(buffer))
\r
2037 buffer = ByteBuffer.wrap(buffer); // May throw
\r
2038 var le = buffer.littleEndian;
\r
2040 var msg = T.decode(buffer.LE(), length);
\r
2050 * Decodes a varint32 length-delimited message from the specified buffer or string.
\r
2051 * @name ProtoBuf.Builder.Message.decodeDelimited
\r
2053 * @param {!ByteBuffer|!ArrayBuffer|!Buffer|string} buffer Buffer to decode from
\r
2054 * @param {string=} enc Encoding if buffer is a string: hex, utf8 (not recommended), defaults to base64
\r
2055 * @return {ProtoBuf.Builder.Message} Decoded message or `null` if not enough bytes are available yet
\r
2056 * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still
\r
2057 * returns the decoded message with missing fields in the `decoded` property on the error.
\r
2060 Message.decodeDelimited = function(buffer, enc) {
\r
2061 if (typeof buffer === 'string')
\r
2062 buffer = ByteBuffer.wrap(buffer, enc ? enc : "base64");
\r
2063 else if (!ByteBuffer.isByteBuffer(buffer))
\r
2064 buffer = ByteBuffer.wrap(buffer); // May throw
\r
2065 if (buffer.remaining() < 1)
\r
2067 var off = buffer.offset,
\r
2068 len = buffer.readVarint32();
\r
2069 if (buffer.remaining() < len) {
\r
2070 buffer.offset = off;
\r
2074 var msg = T.decode(buffer.slice(buffer.offset, buffer.offset + len).LE());
\r
2075 buffer.offset += len;
\r
2078 buffer.offset += len;
\r
2084 * Decodes the message from the specified base64 encoded string.
\r
2085 * @name ProtoBuf.Builder.Message.decode64
\r
2087 * @param {string} str String to decode from
\r
2088 * @return {!ProtoBuf.Builder.Message} Decoded message
\r
2089 * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still
\r
2090 * returns the decoded message with missing fields in the `decoded` property on the error.
\r
2093 Message.decode64 = function(str) {
\r
2094 return Message.decode(str, "base64");
\r
2098 * Decodes the message from the specified hex encoded string.
\r
2099 * @name ProtoBuf.Builder.Message.decodeHex
\r
2101 * @param {string} str String to decode from
\r
2102 * @return {!ProtoBuf.Builder.Message} Decoded message
\r
2103 * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still
\r
2104 * returns the decoded message with missing fields in the `decoded` property on the error.
\r
2107 Message.decodeHex = function(str) {
\r
2108 return Message.decode(str, "hex");
\r
2112 * Decodes the message from a JSON string.
\r
2113 * @name ProtoBuf.Builder.Message.decodeJSON
\r
2115 * @param {string} str String to decode from
\r
2116 * @return {!ProtoBuf.Builder.Message} Decoded message
\r
2117 * @throws {Error} If the message cannot be decoded or if required fields are
\r
2121 Message.decodeJSON = function(str) {
\r
2122 return new Message(JSON.parse(str));
\r
2128 * Returns a string representation of this Message.
\r
2129 * @name ProtoBuf.Builder.Message#toString
\r
2131 * @return {string} String representation as of ".Fully.Qualified.MessageName"
\r
2134 MessagePrototype.toString = function() {
\r
2135 return T.toString();
\r
2141 * Message options.
\r
2142 * @name ProtoBuf.Builder.Message.$options
\r
2143 * @type {Object.<string,*>}
\r
2146 var $optionsS; // cc needs this
\r
2149 * Message options.
\r
2150 * @name ProtoBuf.Builder.Message#$options
\r
2151 * @type {Object.<string,*>}
\r
2157 * Reflection type.
\r
2158 * @name ProtoBuf.Builder.Message.$type
\r
2159 * @type {!ProtoBuf.Reflect.Message}
\r
2165 * Reflection type.
\r
2166 * @name ProtoBuf.Builder.Message#$type
\r
2167 * @type {!ProtoBuf.Reflect.Message}
\r
2172 if (Object.defineProperty)
\r
2173 Object.defineProperty(Message, '$options', { "value": T.buildOpt() }),
\r
2174 Object.defineProperty(MessagePrototype, "$options", { "value": Message["$options"] }),
\r
2175 Object.defineProperty(Message, "$type", { "value": T }),
\r
2176 Object.defineProperty(MessagePrototype, "$type", { "value": T });
\r
2180 })(ProtoBuf, this);
\r
2182 // Static enums and prototyped sub-messages / cached collections
\r
2183 this._fields = [];
\r
2184 this._fieldsById = {};
\r
2185 this._fieldsByName = {};
\r
2186 this._oneofsByName = {};
\r
2187 for (var i=0, k=this.children.length, child; i<k; i++) {
\r
2188 child = this.children[i];
\r
2189 if (child instanceof Enum || child instanceof Message || child instanceof Service) {
\r
2190 if (clazz.hasOwnProperty(child.name))
\r
2191 throw Error("Illegal reflect child of "+this.toString(true)+": "+child.toString(true)+" cannot override static property '"+child.name+"'");
\r
2192 clazz[child.name] = child.build();
\r
2193 } else if (child instanceof Message.Field)
\r
2195 this._fields.push(child),
\r
2196 this._fieldsById[child.id] = child,
\r
2197 this._fieldsByName[child.name] = child;
\r
2198 else if (child instanceof Message.OneOf) {
\r
2199 this._oneofsByName[child.name] = child;
\r
2201 else if (!(child instanceof Message.OneOf) && !(child instanceof Extension)) // Not built
\r
2202 throw Error("Illegal reflect child of "+this.toString(true)+": "+this.children[i].toString(true));
\r
2205 return this.clazz = clazz;
\r
2209 * Encodes a runtime message's contents to the specified buffer.
\r
2210 * @param {!ProtoBuf.Builder.Message} message Runtime message to encode
\r
2211 * @param {ByteBuffer} buffer ByteBuffer to write to
\r
2212 * @param {boolean=} noVerify Whether to not verify field values, defaults to `false`
\r
2213 * @return {ByteBuffer} The ByteBuffer for chaining
\r
2214 * @throws {Error} If required fields are missing or the message cannot be encoded for another reason
\r
2217 MessagePrototype.encode = function(message, buffer, noVerify) {
\r
2218 var fieldMissing = null,
\r
2220 for (var i=0, k=this._fields.length, val; i<k; ++i) {
\r
2221 field = this._fields[i];
\r
2222 val = message[field.name];
\r
2223 if (field.required && val === null) {
\r
2224 if (fieldMissing === null)
\r
2225 fieldMissing = field;
\r
2227 field.encode(noVerify ? val : field.verifyValue(val), buffer, message);
\r
2229 if (fieldMissing !== null) {
\r
2230 var err = Error("Missing at least one required field for "+this.toString(true)+": "+fieldMissing);
\r
2231 err["encoded"] = buffer; // Still expose what we got
\r
2238 * Calculates a runtime message's byte length.
\r
2239 * @param {!ProtoBuf.Builder.Message} message Runtime message to encode
\r
2240 * @returns {number} Byte length
\r
2241 * @throws {Error} If required fields are missing or the message cannot be calculated for another reason
\r
2244 MessagePrototype.calculate = function(message) {
\r
2245 for (var n=0, i=0, k=this._fields.length, field, val; i<k; ++i) {
\r
2246 field = this._fields[i];
\r
2247 val = message[field.name];
\r
2248 if (field.required && val === null)
\r
2249 throw Error("Missing at least one required field for "+this.toString(true)+": "+field);
\r
2251 n += field.calculate(val, message);
\r
2257 * Skips all data until the end of the specified group has been reached.
\r
2258 * @param {number} expectedId Expected GROUPEND id
\r
2259 * @param {!ByteBuffer} buf ByteBuffer
\r
2260 * @returns {boolean} `true` if a value as been skipped, `false` if the end has been reached
\r
2261 * @throws {Error} If it wasn't possible to find the end of the group (buffer overrun or end tag mismatch)
\r
2264 function skipTillGroupEnd(expectedId, buf) {
\r
2265 var tag = buf.readVarint32(), // Throws on OOB
\r
2266 wireType = tag & 0x07,
\r
2268 switch (wireType) {
\r
2269 case ProtoBuf.WIRE_TYPES.VARINT:
\r
2270 do tag = buf.readUint8();
\r
2271 while ((tag & 0x80) === 0x80);
\r
2273 case ProtoBuf.WIRE_TYPES.BITS64:
\r
2276 case ProtoBuf.WIRE_TYPES.LDELIM:
\r
2277 tag = buf.readVarint32(); // reads the varint
\r
2278 buf.offset += tag; // skips n bytes
\r
2280 case ProtoBuf.WIRE_TYPES.STARTGROUP:
\r
2281 skipTillGroupEnd(id, buf);
\r
2283 case ProtoBuf.WIRE_TYPES.ENDGROUP:
\r
2284 if (id === expectedId)
\r
2287 throw Error("Illegal GROUPEND after unknown group: "+id+" ("+expectedId+" expected)");
\r
2288 case ProtoBuf.WIRE_TYPES.BITS32:
\r
2292 throw Error("Illegal wire type in unknown group "+expectedId+": "+wireType);
\r
2298 * Decodes an encoded message and returns the decoded message.
\r
2299 * @param {ByteBuffer} buffer ByteBuffer to decode from
\r
2300 * @param {number=} length Message length. Defaults to decode all remaining data.
\r
2301 * @param {number=} expectedGroupEndId Expected GROUPEND id if this is a legacy group
\r
2302 * @return {ProtoBuf.Builder.Message} Decoded message
\r
2303 * @throws {Error} If the message cannot be decoded
\r
2306 MessagePrototype.decode = function(buffer, length, expectedGroupEndId) {
\r
2307 if (typeof length !== 'number')
\r
2309 var start = buffer.offset,
\r
2310 msg = new (this.clazz)(),
\r
2311 tag, wireType, id, field;
\r
2312 while (buffer.offset < start+length || (length === -1 && buffer.remaining() > 0)) {
\r
2313 tag = buffer.readVarint32();
\r
2314 wireType = tag & 0x07;
\r
2316 if (wireType === ProtoBuf.WIRE_TYPES.ENDGROUP) {
\r
2317 if (id !== expectedGroupEndId)
\r
2318 throw Error("Illegal group end indicator for "+this.toString(true)+": "+id+" ("+(expectedGroupEndId ? expectedGroupEndId+" expected" : "not a group")+")");
\r
2321 if (!(field = this._fieldsById[id])) {
\r
2322 // "messages created by your new code can be parsed by your old code: old binaries simply ignore the new field when parsing."
\r
2323 switch (wireType) {
\r
2324 case ProtoBuf.WIRE_TYPES.VARINT:
\r
2325 buffer.readVarint32();
\r
2327 case ProtoBuf.WIRE_TYPES.BITS32:
\r
2328 buffer.offset += 4;
\r
2330 case ProtoBuf.WIRE_TYPES.BITS64:
\r
2331 buffer.offset += 8;
\r
2333 case ProtoBuf.WIRE_TYPES.LDELIM:
\r
2334 var len = buffer.readVarint32();
\r
2335 buffer.offset += len;
\r
2337 case ProtoBuf.WIRE_TYPES.STARTGROUP:
\r
2338 while (skipTillGroupEnd(id, buffer)) {}
\r
2341 throw Error("Illegal wire type for unknown field "+id+" in "+this.toString(true)+"#decode: "+wireType);
\r
2345 if (field.repeated && !field.options["packed"]) {
\r
2346 msg[field.name].push(field.decode(wireType, buffer));
\r
2347 } else if (field.map) {
\r
2348 var keyval = field.decode(wireType, buffer);
\r
2349 msg[field.name].set(keyval[0], keyval[1]);
\r
2351 msg[field.name] = field.decode(wireType, buffer);
\r
2352 if (field.oneof) { // Field is part of an OneOf (not a virtual OneOf field)
\r
2353 var currentField = msg[field.oneof.name]; // Virtual field references currently set field
\r
2354 if (currentField !== null && currentField !== field.name)
\r
2355 msg[currentField] = null; // Clear currently set field
\r
2356 msg[field.oneof.name] = field.name; // Point virtual field at this field
\r
2361 // Check if all required fields are present and set default values for optional fields that are not
\r
2362 for (var i=0, k=this._fields.length; i<k; ++i) {
\r
2363 field = this._fields[i];
\r
2364 if (msg[field.name] === null) {
\r
2365 if (this.syntax === "proto3") { // Proto3 sets default values by specification
\r
2366 msg[field.name] = field.defaultValue;
\r
2367 } else if (field.required) {
\r
2368 var err = Error("Missing at least one required field for " + this.toString(true) + ": " + field.name);
\r
2369 err["decoded"] = msg; // Still expose what we got
\r
2371 } else if (ProtoBuf.populateDefaults && field.defaultValue !== null)
\r
2372 msg[field.name] = field.defaultValue;
\r
2379 * @alias ProtoBuf.Reflect.Message
\r
2382 Reflect.Message = Message;
\r
2385 * Constructs a new Message Field.
\r
2386 * @exports ProtoBuf.Reflect.Message.Field
\r
2387 * @param {!ProtoBuf.Builder} builder Builder reference
\r
2388 * @param {!ProtoBuf.Reflect.Message} message Message reference
\r
2389 * @param {string} rule Rule, one of requried, optional, repeated
\r
2390 * @param {string?} keytype Key data type, if any.
\r
2391 * @param {string} type Data type, e.g. int32
\r
2392 * @param {string} name Field name
\r
2393 * @param {number} id Unique field id
\r
2394 * @param {Object.<string,*>=} options Options
\r
2395 * @param {!ProtoBuf.Reflect.Message.OneOf=} oneof Enclosing OneOf
\r
2396 * @param {string?} syntax The syntax level of this definition (e.g., proto3)
\r
2398 * @extends ProtoBuf.Reflect.T
\r
2400 var Field = function(builder, message, rule, keytype, type, name, id, options, oneof, syntax) {
\r
2401 T.call(this, builder, message, name);
\r
2406 this.className = "Message.Field";
\r
2409 * Message field required flag.
\r
2413 this.required = rule === "required";
\r
2416 * Message field repeated flag.
\r
2420 this.repeated = rule === "repeated";
\r
2423 * Message field map flag.
\r
2427 this.map = rule === "map";
\r
2430 * Message field key type. Type reference string if unresolved, protobuf
\r
2431 * type if resolved. Valid only if this.map === true, null otherwise.
\r
2432 * @type {string|{name: string, wireType: number}|null}
\r
2435 this.keyType = keytype || null;
\r
2438 * Message field type. Type reference string if unresolved, protobuf type if
\r
2439 * resolved. In a map field, this is the value type.
\r
2440 * @type {string|{name: string, wireType: number}}
\r
2446 * Resolved type reference inside the global namespace.
\r
2447 * @type {ProtoBuf.Reflect.T|null}
\r
2450 this.resolvedType = null;
\r
2453 * Unique message field id.
\r
2460 * Message field options.
\r
2461 * @type {!Object.<string,*>}
\r
2465 this.options = options || {};
\r
2472 this.defaultValue = null;
\r
2475 * Enclosing OneOf.
\r
2476 * @type {?ProtoBuf.Reflect.Message.OneOf}
\r
2479 this.oneof = oneof || null;
\r
2482 * Syntax level of this definition (e.g., proto3).
\r
2486 this.syntax = syntax || 'proto2';
\r
2489 * Original field name.
\r
2493 this.originalName = this.name; // Used to revert camelcase transformation on naming collisions
\r
2496 * Element implementation. Created in build() after types are resolved.
\r
2497 * @type {ProtoBuf.Element}
\r
2500 this.element = null;
\r
2503 * Key element implementation, for map fields. Created in build() after
\r
2504 * types are resolved.
\r
2505 * @type {ProtoBuf.Element}
\r
2508 this.keyElement = null;
\r
2510 // Convert field names to camel case notation if the override is set
\r
2511 if (this.builder.options['convertFieldsToCamelCase'] && !(this instanceof Message.ExtensionField))
\r
2512 this.name = ProtoBuf.Util.toCamelCase(this.name);
\r
2516 * @alias ProtoBuf.Reflect.Message.Field.prototype
\r
2519 var FieldPrototype = Field.prototype = Object.create(T.prototype);
\r
2522 * Builds the field.
\r
2526 FieldPrototype.build = function() {
\r
2527 this.element = new Element(this.type, this.resolvedType, false, this.syntax, this.name);
\r
2529 this.keyElement = new Element(this.keyType, undefined, true, this.syntax, this.name);
\r
2531 // In proto3, fields do not have field presence, and every field is set to
\r
2532 // its type's default value ("", 0, 0.0, or false).
\r
2533 if (this.syntax === 'proto3' && !this.repeated && !this.map)
\r
2534 this.defaultValue = Element.defaultFieldValue(this.type);
\r
2536 // Otherwise, default values are present when explicitly specified
\r
2537 else if (typeof this.options['default'] !== 'undefined')
\r
2538 this.defaultValue = this.verifyValue(this.options['default']);
\r
2542 * Checks if the given value can be set for this field.
\r
2543 * @param {*} value Value to check
\r
2544 * @param {boolean=} skipRepeated Whether to skip the repeated value check or not. Defaults to false.
\r
2545 * @return {*} Verified, maybe adjusted, value
\r
2546 * @throws {Error} If the value cannot be set for this field
\r
2549 FieldPrototype.verifyValue = function(value, skipRepeated) {
\r
2550 skipRepeated = skipRepeated || false;
\r
2552 function fail(val, msg) {
\r
2553 throw Error("Illegal value for "+self.toString(true)+" of type "+self.type.name+": "+val+" ("+msg+")");
\r
2555 if (value === null) { // NULL values for optional fields
\r
2556 if (this.required)
\r
2557 fail(typeof value, "required");
\r
2558 if (this.syntax === 'proto3' && this.type !== ProtoBuf.TYPES["message"])
\r
2559 fail(typeof value, "proto3 field without field presence cannot be null");
\r
2563 if (this.repeated && !skipRepeated) { // Repeated values as arrays
\r
2564 if (!Array.isArray(value))
\r
2567 for (i=0; i<value.length; i++)
\r
2568 res.push(this.element.verifyValue(value[i]));
\r
2571 if (this.map && !skipRepeated) { // Map values as objects
\r
2572 if (!(value instanceof ProtoBuf.Map)) {
\r
2573 // If not already a Map, attempt to convert.
\r
2574 if (!(value instanceof Object)) {
\r
2575 fail(typeof value,
\r
2576 "expected ProtoBuf.Map or raw object for map field");
\r
2578 return new ProtoBuf.Map(this, value);
\r
2583 // All non-repeated fields expect no array
\r
2584 if (!this.repeated && Array.isArray(value))
\r
2585 fail(typeof value, "no array expected");
\r
2587 return this.element.verifyValue(value);
\r
2591 * Determines whether the field will have a presence on the wire given its
\r
2593 * @param {*} value Verified field value
\r
2594 * @param {!ProtoBuf.Builder.Message} message Runtime message
\r
2595 * @return {boolean} Whether the field will be present on the wire
\r
2597 FieldPrototype.hasWirePresence = function(value, message) {
\r
2598 if (this.syntax !== 'proto3')
\r
2599 return (value !== null);
\r
2600 if (this.oneof && message[this.oneof.name] === this.name)
\r
2602 switch (this.type) {
\r
2603 case ProtoBuf.TYPES["int32"]:
\r
2604 case ProtoBuf.TYPES["sint32"]:
\r
2605 case ProtoBuf.TYPES["sfixed32"]:
\r
2606 case ProtoBuf.TYPES["uint32"]:
\r
2607 case ProtoBuf.TYPES["fixed32"]:
\r
2608 return value !== 0;
\r
2610 case ProtoBuf.TYPES["int64"]:
\r
2611 case ProtoBuf.TYPES["sint64"]:
\r
2612 case ProtoBuf.TYPES["sfixed64"]:
\r
2613 case ProtoBuf.TYPES["uint64"]:
\r
2614 case ProtoBuf.TYPES["fixed64"]:
\r
2615 return value.low !== 0 || value.high !== 0;
\r
2617 case ProtoBuf.TYPES["bool"]:
\r
2620 case ProtoBuf.TYPES["float"]:
\r
2621 case ProtoBuf.TYPES["double"]:
\r
2622 return value !== 0.0;
\r
2624 case ProtoBuf.TYPES["string"]:
\r
2625 return value.length > 0;
\r
2627 case ProtoBuf.TYPES["bytes"]:
\r
2628 return value.remaining() > 0;
\r
2630 case ProtoBuf.TYPES["enum"]:
\r
2631 return value !== 0;
\r
2633 case ProtoBuf.TYPES["message"]:
\r
2634 return value !== null;
\r
2641 * Encodes the specified field value to the specified buffer.
\r
2642 * @param {*} value Verified field value
\r
2643 * @param {ByteBuffer} buffer ByteBuffer to encode to
\r
2644 * @param {!ProtoBuf.Builder.Message} message Runtime message
\r
2645 * @return {ByteBuffer} The ByteBuffer for chaining
\r
2646 * @throws {Error} If the field cannot be encoded
\r
2649 FieldPrototype.encode = function(value, buffer, message) {
\r
2650 if (this.type === null || typeof this.type !== 'object')
\r
2651 throw Error("[INTERNAL] Unresolved type in "+this.toString(true)+": "+this.type);
\r
2652 if (value === null || (this.repeated && value.length == 0))
\r
2653 return buffer; // Optional omitted
\r
2655 if (this.repeated) {
\r
2657 // "Only repeated fields of primitive numeric types (types which use the varint, 32-bit, or 64-bit wire
\r
2658 // types) can be declared 'packed'."
\r
2659 if (this.options["packed"] && ProtoBuf.PACKABLE_WIRE_TYPES.indexOf(this.type.wireType) >= 0) {
\r
2660 // "All of the elements of the field are packed into a single key-value pair with wire type 2
\r
2661 // (length-delimited). Each element is encoded the same way it would be normally, except without a
\r
2662 // tag preceding it."
\r
2663 buffer.writeVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM);
\r
2664 buffer.ensureCapacity(buffer.offset += 1); // We do not know the length yet, so let's assume a varint of length 1
\r
2665 var start = buffer.offset; // Remember where the contents begin
\r
2666 for (i=0; i<value.length; i++)
\r
2667 this.element.encodeValue(this.id, value[i], buffer);
\r
2668 var len = buffer.offset-start,
\r
2669 varintLen = ByteBuffer.calculateVarint32(len);
\r
2670 if (varintLen > 1) { // We need to move the contents
\r
2671 var contents = buffer.slice(start, buffer.offset);
\r
2672 start += varintLen-1;
\r
2673 buffer.offset = start;
\r
2674 buffer.append(contents);
\r
2676 buffer.writeVarint32(len, start-varintLen);
\r
2678 // "If your message definition has repeated elements (without the [packed=true] option), the encoded
\r
2679 // message has zero or more key-value pairs with the same tag number"
\r
2680 for (i=0; i<value.length; i++)
\r
2681 buffer.writeVarint32((this.id << 3) | this.type.wireType),
\r
2682 this.element.encodeValue(this.id, value[i], buffer);
\r
2684 } else if (this.map) {
\r
2685 // Write out each map entry as a submessage.
\r
2686 value.forEach(function(val, key, m) {
\r
2687 // Compute the length of the submessage (key, val) pair.
\r
2689 ByteBuffer.calculateVarint32((1 << 3) | this.keyType.wireType) +
\r
2690 this.keyElement.calculateLength(1, key) +
\r
2691 ByteBuffer.calculateVarint32((2 << 3) | this.type.wireType) +
\r
2692 this.element.calculateLength(2, val);
\r
2694 // Submessage with wire type of length-delimited.
\r
2695 buffer.writeVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM);
\r
2696 buffer.writeVarint32(length);
\r
2698 // Write out the key and val.
\r
2699 buffer.writeVarint32((1 << 3) | this.keyType.wireType);
\r
2700 this.keyElement.encodeValue(1, key, buffer);
\r
2701 buffer.writeVarint32((2 << 3) | this.type.wireType);
\r
2702 this.element.encodeValue(2, val, buffer);
\r
2705 if (this.hasWirePresence(value, message)) {
\r
2706 buffer.writeVarint32((this.id << 3) | this.type.wireType);
\r
2707 this.element.encodeValue(this.id, value, buffer);
\r
2711 throw Error("Illegal value for "+this.toString(true)+": "+value+" ("+e+")");
\r
2717 * Calculates the length of this field's value on the network level.
\r
2718 * @param {*} value Field value
\r
2719 * @param {!ProtoBuf.Builder.Message} message Runtime message
\r
2720 * @returns {number} Byte length
\r
2723 FieldPrototype.calculate = function(value, message) {
\r
2724 value = this.verifyValue(value); // May throw
\r
2725 if (this.type === null || typeof this.type !== 'object')
\r
2726 throw Error("[INTERNAL] Unresolved type in "+this.toString(true)+": "+this.type);
\r
2727 if (value === null || (this.repeated && value.length == 0))
\r
2728 return 0; // Optional omitted
\r
2731 if (this.repeated) {
\r
2733 if (this.options["packed"] && ProtoBuf.PACKABLE_WIRE_TYPES.indexOf(this.type.wireType) >= 0) {
\r
2734 n += ByteBuffer.calculateVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM);
\r
2736 for (i=0; i<value.length; i++)
\r
2737 ni += this.element.calculateLength(this.id, value[i]);
\r
2738 n += ByteBuffer.calculateVarint32(ni);
\r
2741 for (i=0; i<value.length; i++)
\r
2742 n += ByteBuffer.calculateVarint32((this.id << 3) | this.type.wireType),
\r
2743 n += this.element.calculateLength(this.id, value[i]);
\r
2745 } else if (this.map) {
\r
2746 // Each map entry becomes a submessage.
\r
2747 value.forEach(function(val, key, m) {
\r
2748 // Compute the length of the submessage (key, val) pair.
\r
2750 ByteBuffer.calculateVarint32((1 << 3) | this.keyType.wireType) +
\r
2751 this.keyElement.calculateLength(1, key) +
\r
2752 ByteBuffer.calculateVarint32((2 << 3) | this.type.wireType) +
\r
2753 this.element.calculateLength(2, val);
\r
2755 n += ByteBuffer.calculateVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM);
\r
2756 n += ByteBuffer.calculateVarint32(length);
\r
2760 if (this.hasWirePresence(value, message)) {
\r
2761 n += ByteBuffer.calculateVarint32((this.id << 3) | this.type.wireType);
\r
2762 n += this.element.calculateLength(this.id, value);
\r
2766 throw Error("Illegal value for "+this.toString(true)+": "+value+" ("+e+")");
\r
2772 * Decode the field value from the specified buffer.
\r
2773 * @param {number} wireType Leading wire type
\r
2774 * @param {ByteBuffer} buffer ByteBuffer to decode from
\r
2775 * @param {boolean=} skipRepeated Whether to skip the repeated check or not. Defaults to false.
\r
2776 * @return {*} Decoded value: array for packed repeated fields, [key, value] for
\r
2777 * map fields, or an individual value otherwise.
\r
2778 * @throws {Error} If the field cannot be decoded
\r
2781 FieldPrototype.decode = function(wireType, buffer, skipRepeated) {
\r
2782 var value, nBytes;
\r
2784 // We expect wireType to match the underlying type's wireType unless we see
\r
2785 // a packed repeated field, or unless this is a map field.
\r
2787 (!this.map && wireType == this.type.wireType) ||
\r
2788 (!skipRepeated && this.repeated && this.options["packed"] &&
\r
2789 wireType == ProtoBuf.WIRE_TYPES.LDELIM) ||
\r
2790 (this.map && wireType == ProtoBuf.WIRE_TYPES.LDELIM);
\r
2792 throw Error("Illegal wire type for field "+this.toString(true)+": "+wireType+" ("+this.type.wireType+" expected)");
\r
2794 // Handle packed repeated fields.
\r
2795 if (wireType == ProtoBuf.WIRE_TYPES.LDELIM && this.repeated && this.options["packed"] && ProtoBuf.PACKABLE_WIRE_TYPES.indexOf(this.type.wireType) >= 0) {
\r
2796 if (!skipRepeated) {
\r
2797 nBytes = buffer.readVarint32();
\r
2798 nBytes = buffer.offset + nBytes; // Limit
\r
2800 while (buffer.offset < nBytes)
\r
2801 values.push(this.decode(this.type.wireType, buffer, true));
\r
2804 // Read the next value otherwise...
\r
2809 // Read one (key, value) submessage, and return [key, value]
\r
2810 var key = Element.defaultFieldValue(this.keyType);
\r
2811 value = Element.defaultFieldValue(this.type);
\r
2813 // Read the length
\r
2814 nBytes = buffer.readVarint32();
\r
2815 if (buffer.remaining() < nBytes)
\r
2816 throw Error("Illegal number of bytes for "+this.toString(true)+": "+nBytes+" required but got only "+buffer.remaining());
\r
2818 // Get a sub-buffer of this key/value submessage
\r
2819 var msgbuf = buffer.clone();
\r
2820 msgbuf.limit = msgbuf.offset + nBytes;
\r
2821 buffer.offset += nBytes;
\r
2823 while (msgbuf.remaining() > 0) {
\r
2824 var tag = msgbuf.readVarint32();
\r
2825 wireType = tag & 0x07;
\r
2826 var id = tag >>> 3;
\r
2828 key = this.keyElement.decode(msgbuf, wireType, id);
\r
2829 } else if (id === 2) {
\r
2830 value = this.element.decode(msgbuf, wireType, id);
\r
2832 throw Error("Unexpected tag in map field key/value submessage");
\r
2836 return [key, value];
\r
2839 // Handle singular and non-packed repeated field values.
\r
2840 return this.element.decode(buffer, wireType, this.id);
\r
2844 * @alias ProtoBuf.Reflect.Message.Field
\r
2847 Reflect.Message.Field = Field;
\r
2850 * Constructs a new Message ExtensionField.
\r
2851 * @exports ProtoBuf.Reflect.Message.ExtensionField
\r
2852 * @param {!ProtoBuf.Builder} builder Builder reference
\r
2853 * @param {!ProtoBuf.Reflect.Message} message Message reference
\r
2854 * @param {string} rule Rule, one of requried, optional, repeated
\r
2855 * @param {string} type Data type, e.g. int32
\r
2856 * @param {string} name Field name
\r
2857 * @param {number} id Unique field id
\r
2858 * @param {!Object.<string,*>=} options Options
\r
2860 * @extends ProtoBuf.Reflect.Message.Field
\r
2862 var ExtensionField = function(builder, message, rule, type, name, id, options) {
\r
2863 Field.call(this, builder, message, rule, /* keytype = */ null, type, name, id, options);
\r
2866 * Extension reference.
\r
2867 * @type {!ProtoBuf.Reflect.Extension}
\r
2874 ExtensionField.prototype = Object.create(Field.prototype);
\r
2877 * @alias ProtoBuf.Reflect.Message.ExtensionField
\r
2880 Reflect.Message.ExtensionField = ExtensionField;
\r
2883 * Constructs a new Message OneOf.
\r
2884 * @exports ProtoBuf.Reflect.Message.OneOf
\r
2885 * @param {!ProtoBuf.Builder} builder Builder reference
\r
2886 * @param {!ProtoBuf.Reflect.Message} message Message reference
\r
2887 * @param {string} name OneOf name
\r
2889 * @extends ProtoBuf.Reflect.T
\r
2891 var OneOf = function(builder, message, name) {
\r
2892 T.call(this, builder, message, name);
\r
2895 * Enclosed fields.
\r
2896 * @type {!Array.<!ProtoBuf.Reflect.Message.Field>}
\r
2903 * @alias ProtoBuf.Reflect.Message.OneOf
\r
2906 Reflect.Message.OneOf = OneOf;
\r
2909 * Constructs a new Enum.
\r
2910 * @exports ProtoBuf.Reflect.Enum
\r
2911 * @param {!ProtoBuf.Builder} builder Builder reference
\r
2912 * @param {!ProtoBuf.Reflect.T} parent Parent Reflect object
\r
2913 * @param {string} name Enum name
\r
2914 * @param {Object.<string,*>=} options Enum options
\r
2915 * @param {string?} syntax The syntax level (e.g., proto3)
\r
2917 * @extends ProtoBuf.Reflect.Namespace
\r
2919 var Enum = function(builder, parent, name, options, syntax) {
\r
2920 Namespace.call(this, builder, parent, name, options, syntax);
\r
2925 this.className = "Enum";
\r
2928 * Runtime enum object.
\r
2929 * @type {Object.<string,number>|null}
\r
2932 this.object = null;
\r
2936 * Gets the string name of an enum value.
\r
2937 * @param {!ProtoBuf.Builder.Enum} enm Runtime enum
\r
2938 * @param {number} value Enum value
\r
2939 * @returns {?string} Name or `null` if not present
\r
2942 Enum.getName = function(enm, value) {
\r
2943 var keys = Object.keys(enm);
\r
2944 for (var i=0, key; i<keys.length; ++i)
\r
2945 if (enm[key = keys[i]] === value)
\r
2951 * @alias ProtoBuf.Reflect.Enum.prototype
\r
2954 var EnumPrototype = Enum.prototype = Object.create(Namespace.prototype);
\r
2957 * Builds this enum and returns the runtime counterpart.
\r
2958 * @param {boolean} rebuild Whether to rebuild or not, defaults to false
\r
2959 * @returns {!Object.<string,number>}
\r
2962 EnumPrototype.build = function(rebuild) {
\r
2963 if (this.object && !rebuild)
\r
2964 return this.object;
\r
2965 var enm = new ProtoBuf.Builder.Enum(),
\r
2966 values = this.getChildren(Enum.Value);
\r
2967 for (var i=0, k=values.length; i<k; ++i)
\r
2968 enm[values[i]['name']] = values[i]['id'];
\r
2969 if (Object.defineProperty)
\r
2970 Object.defineProperty(enm, '$options', {
\r
2971 "value": this.buildOpt(),
\r
2972 "enumerable": false
\r
2974 return this.object = enm;
\r
2978 * @alias ProtoBuf.Reflect.Enum
\r
2981 Reflect.Enum = Enum;
\r
2984 * Constructs a new Enum Value.
\r
2985 * @exports ProtoBuf.Reflect.Enum.Value
\r
2986 * @param {!ProtoBuf.Builder} builder Builder reference
\r
2987 * @param {!ProtoBuf.Reflect.Enum} enm Enum reference
\r
2988 * @param {string} name Field name
\r
2989 * @param {number} id Unique field id
\r
2991 * @extends ProtoBuf.Reflect.T
\r
2993 var Value = function(builder, enm, name, id) {
\r
2994 T.call(this, builder, enm, name);
\r
2999 this.className = "Enum.Value";
\r
3002 * Unique enum value id.
\r
3010 Value.prototype = Object.create(T.prototype);
\r
3013 * @alias ProtoBuf.Reflect.Enum.Value
\r
3016 Reflect.Enum.Value = Value;
\r
3019 * An extension (field).
\r
3020 * @exports ProtoBuf.Reflect.Extension
\r
3022 * @param {!ProtoBuf.Builder} builder Builder reference
\r
3023 * @param {!ProtoBuf.Reflect.T} parent Parent object
\r
3024 * @param {string} name Object name
\r
3025 * @param {!ProtoBuf.Reflect.Message.Field} field Extension field
\r
3027 var Extension = function(builder, parent, name, field) {
\r
3028 T.call(this, builder, parent, name);
\r
3031 * Extended message field.
\r
3032 * @type {!ProtoBuf.Reflect.Message.Field}
\r
3035 this.field = field;
\r
3039 Extension.prototype = Object.create(T.prototype);
\r
3042 * @alias ProtoBuf.Reflect.Extension
\r
3045 Reflect.Extension = Extension;
\r
3048 * Constructs a new Service.
\r
3049 * @exports ProtoBuf.Reflect.Service
\r
3050 * @param {!ProtoBuf.Builder} builder Builder reference
\r
3051 * @param {!ProtoBuf.Reflect.Namespace} root Root
\r
3052 * @param {string} name Service name
\r
3053 * @param {Object.<string,*>=} options Options
\r
3055 * @extends ProtoBuf.Reflect.Namespace
\r
3057 var Service = function(builder, root, name, options) {
\r
3058 Namespace.call(this, builder, root, name, options);
\r
3063 this.className = "Service";
\r
3066 * Built runtime service class.
\r
3067 * @type {?function(new:ProtoBuf.Builder.Service)}
\r
3069 this.clazz = null;
\r
3073 * @alias ProtoBuf.Reflect.Service.prototype
\r
3076 var ServicePrototype = Service.prototype = Object.create(Namespace.prototype);
\r
3079 * Builds the service and returns the runtime counterpart, which is a fully functional class.
\r
3080 * @see ProtoBuf.Builder.Service
\r
3081 * @param {boolean=} rebuild Whether to rebuild or not
\r
3082 * @return {Function} Service class
\r
3083 * @throws {Error} If the message cannot be built
\r
3086 ServicePrototype.build = function(rebuild) {
\r
3087 if (this.clazz && !rebuild)
\r
3088 return this.clazz;
\r
3090 // Create the runtime Service class in its own scope
\r
3091 return this.clazz = (function(ProtoBuf, T) {
\r
3094 * Constructs a new runtime Service.
\r
3095 * @name ProtoBuf.Builder.Service
\r
3096 * @param {function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))=} rpcImpl RPC implementation receiving the method name and the message
\r
3097 * @class Barebone of all runtime services.
\r
3099 * @throws {Error} If the service cannot be created
\r
3101 var Service = function(rpcImpl) {
\r
3102 ProtoBuf.Builder.Service.call(this);
\r
3105 * Service implementation.
\r
3106 * @name ProtoBuf.Builder.Service#rpcImpl
\r
3107 * @type {!function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))}
\r
3110 this.rpcImpl = rpcImpl || function(name, msg, callback) {
\r
3111 // This is what a user has to implement: A function receiving the method name, the actual message to
\r
3112 // send (type checked) and the callback that's either provided with the error as its first
\r
3113 // argument or null and the actual response message.
\r
3114 setTimeout(callback.bind(this, Error("Not implemented, see: https://github.com/dcodeIO/ProtoBuf.js/wiki/Services")), 0); // Must be async!
\r
3119 * @alias ProtoBuf.Builder.Service.prototype
\r
3122 var ServicePrototype = Service.prototype = Object.create(ProtoBuf.Builder.Service.prototype);
\r
3125 * Asynchronously performs an RPC call using the given RPC implementation.
\r
3126 * @name ProtoBuf.Builder.Service.[Method]
\r
3128 * @param {!function(string, ProtoBuf.Builder.Message, function(Error, ProtoBuf.Builder.Message=))} rpcImpl RPC implementation
\r
3129 * @param {ProtoBuf.Builder.Message} req Request
\r
3130 * @param {function(Error, (ProtoBuf.Builder.Message|ByteBuffer|Buffer|string)=)} callback Callback receiving
\r
3131 * the error if any and the response either as a pre-parsed message or as its raw bytes
\r
3136 * Asynchronously performs an RPC call using the instance's RPC implementation.
\r
3137 * @name ProtoBuf.Builder.Service#[Method]
\r
3139 * @param {ProtoBuf.Builder.Message} req Request
\r
3140 * @param {function(Error, (ProtoBuf.Builder.Message|ByteBuffer|Buffer|string)=)} callback Callback receiving
\r
3141 * the error if any and the response either as a pre-parsed message or as its raw bytes
\r
3145 var rpc = T.getChildren(ProtoBuf.Reflect.Service.RPCMethod);
\r
3146 for (var i=0; i<rpc.length; i++) {
\r
3147 (function(method) {
\r
3149 // service#Method(message, callback)
\r
3150 ServicePrototype[method.name] = function(req, callback) {
\r
3153 // If given as a buffer, decode the request. Will throw a TypeError if not a valid buffer.
\r
3154 req = method.resolvedRequestType.clazz.decode(ByteBuffer.wrap(req));
\r
3156 if (!(err instanceof TypeError))
\r
3159 if (req === null || typeof req !== 'object')
\r
3160 throw Error("Illegal arguments");
\r
3161 if (!(req instanceof method.resolvedRequestType.clazz))
\r
3162 req = new method.resolvedRequestType.clazz(req);
\r
3163 this.rpcImpl(method.fqn(), req, function(err, res) { // Assumes that this is properly async
\r
3168 // Coalesce to empty string when service response has empty content
\r
3171 try { res = method.resolvedResponseType.clazz.decode(res); } catch (notABuffer) {}
\r
3172 if (!res || !(res instanceof method.resolvedResponseType.clazz)) {
\r
3173 callback(Error("Illegal response type received in service method "+ T.name+"#"+method.name));
\r
3176 callback(null, res);
\r
3179 setTimeout(callback.bind(this, err), 0);
\r
3183 // Service.Method(rpcImpl, message, callback)
\r
3184 Service[method.name] = function(rpcImpl, req, callback) {
\r
3185 new Service(rpcImpl)[method.name](req, callback);
\r
3188 if (Object.defineProperty)
\r
3189 Object.defineProperty(Service[method.name], "$options", { "value": method.buildOpt() }),
\r
3190 Object.defineProperty(ServicePrototype[method.name], "$options", { "value": Service[method.name]["$options"] });
\r
3197 * Service options.
\r
3198 * @name ProtoBuf.Builder.Service.$options
\r
3199 * @type {Object.<string,*>}
\r
3202 var $optionsS; // cc needs this
\r
3205 * Service options.
\r
3206 * @name ProtoBuf.Builder.Service#$options
\r
3207 * @type {Object.<string,*>}
\r
3213 * Reflection type.
\r
3214 * @name ProtoBuf.Builder.Service.$type
\r
3215 * @type {!ProtoBuf.Reflect.Service}
\r
3221 * Reflection type.
\r
3222 * @name ProtoBuf.Builder.Service#$type
\r
3223 * @type {!ProtoBuf.Reflect.Service}
\r
3228 if (Object.defineProperty)
\r
3229 Object.defineProperty(Service, "$options", { "value": T.buildOpt() }),
\r
3230 Object.defineProperty(ServicePrototype, "$options", { "value": Service["$options"] }),
\r
3231 Object.defineProperty(Service, "$type", { "value": T }),
\r
3232 Object.defineProperty(ServicePrototype, "$type", { "value": T });
\r
3236 })(ProtoBuf, this);
\r
3240 * @alias ProtoBuf.Reflect.Service
\r
3243 Reflect.Service = Service;
\r
3246 * Abstract service method.
\r
3247 * @exports ProtoBuf.Reflect.Service.Method
\r
3248 * @param {!ProtoBuf.Builder} builder Builder reference
\r
3249 * @param {!ProtoBuf.Reflect.Service} svc Service
\r
3250 * @param {string} name Method name
\r
3251 * @param {Object.<string,*>=} options Options
\r
3253 * @extends ProtoBuf.Reflect.T
\r
3255 var Method = function(builder, svc, name, options) {
\r
3256 T.call(this, builder, svc, name);
\r
3261 this.className = "Service.Method";
\r
3265 * @type {Object.<string, *>}
\r
3268 this.options = options || {};
\r
3272 * @alias ProtoBuf.Reflect.Service.Method.prototype
\r
3275 var MethodPrototype = Method.prototype = Object.create(T.prototype);
\r
3278 * Builds the method's '$options' property.
\r
3279 * @name ProtoBuf.Reflect.Service.Method#buildOpt
\r
3281 * @return {Object.<string,*>}
\r
3283 MethodPrototype.buildOpt = NamespacePrototype.buildOpt;
\r
3286 * @alias ProtoBuf.Reflect.Service.Method
\r
3289 Reflect.Service.Method = Method;
\r
3292 * RPC service method.
\r
3293 * @exports ProtoBuf.Reflect.Service.RPCMethod
\r
3294 * @param {!ProtoBuf.Builder} builder Builder reference
\r
3295 * @param {!ProtoBuf.Reflect.Service} svc Service
\r
3296 * @param {string} name Method name
\r
3297 * @param {string} request Request message name
\r
3298 * @param {string} response Response message name
\r
3299 * @param {boolean} request_stream Whether requests are streamed
\r
3300 * @param {boolean} response_stream Whether responses are streamed
\r
3301 * @param {Object.<string,*>=} options Options
\r
3303 * @extends ProtoBuf.Reflect.Service.Method
\r
3305 var RPCMethod = function(builder, svc, name, request, response, request_stream, response_stream, options) {
\r
3306 Method.call(this, builder, svc, name, options);
\r
3311 this.className = "Service.RPCMethod";
\r
3314 * Request message name.
\r
3318 this.requestName = request;
\r
3321 * Response message name.
\r
3325 this.responseName = response;
\r
3328 * Whether requests are streamed
\r
3332 this.requestStream = request_stream;
\r
3335 * Whether responses are streamed
\r
3339 this.responseStream = response_stream;
\r
3342 * Resolved request message type.
\r
3343 * @type {ProtoBuf.Reflect.Message}
\r
3346 this.resolvedRequestType = null;
\r
3349 * Resolved response message type.
\r
3350 * @type {ProtoBuf.Reflect.Message}
\r
3353 this.resolvedResponseType = null;
\r
3357 RPCMethod.prototype = Object.create(Method.prototype);
\r
3360 * @alias ProtoBuf.Reflect.Service.RPCMethod
\r
3363 Reflect.Service.RPCMethod = RPCMethod;
\r
3370 * @alias ProtoBuf.Builder
\r
3373 ProtoBuf.Builder = (function(ProtoBuf, Lang, Reflect) {
\r
3377 * Constructs a new Builder.
\r
3378 * @exports ProtoBuf.Builder
\r
3379 * @class Provides the functionality to build protocol messages.
\r
3380 * @param {Object.<string,*>=} options Options
\r
3383 var Builder = function(options) {
\r
3387 * @type {ProtoBuf.Reflect.Namespace}
\r
3390 this.ns = new Reflect.Namespace(this, null, ""); // Global namespace
\r
3393 * Namespace pointer.
\r
3394 * @type {ProtoBuf.Reflect.T}
\r
3397 this.ptr = this.ns;
\r
3404 this.resolved = false;
\r
3407 * The current building result.
\r
3408 * @type {Object.<string,ProtoBuf.Builder.Message|Object>|null}
\r
3411 this.result = null;
\r
3415 * @type {Array.<string>}
\r
3421 * Import root override.
\r
3425 this.importRoot = null;
\r
3429 * @type {!Object.<string, *>}
\r
3432 this.options = options || {};
\r
3436 * @alias ProtoBuf.Builder.prototype
\r
3439 var BuilderPrototype = Builder.prototype;
\r
3441 // ----- Definition tests -----
\r
3444 * Tests if a definition most likely describes a message.
\r
3445 * @param {!Object} def
\r
3446 * @returns {boolean}
\r
3449 Builder.isMessage = function(def) {
\r
3450 // Messages require a string name
\r
3451 if (typeof def["name"] !== 'string')
\r
3453 // Messages do not contain values (enum) or rpc methods (service)
\r
3454 if (typeof def["values"] !== 'undefined' || typeof def["rpc"] !== 'undefined')
\r
3460 * Tests if a definition most likely describes a message field.
\r
3461 * @param {!Object} def
\r
3462 * @returns {boolean}
\r
3465 Builder.isMessageField = function(def) {
\r
3466 // Message fields require a string rule, name and type and an id
\r
3467 if (typeof def["rule"] !== 'string' || typeof def["name"] !== 'string' || typeof def["type"] !== 'string' || typeof def["id"] === 'undefined')
\r
3473 * Tests if a definition most likely describes an enum.
\r
3474 * @param {!Object} def
\r
3475 * @returns {boolean}
\r
3478 Builder.isEnum = function(def) {
\r
3479 // Enums require a string name
\r
3480 if (typeof def["name"] !== 'string')
\r
3482 // Enums require at least one value
\r
3483 if (typeof def["values"] === 'undefined' || !Array.isArray(def["values"]) || def["values"].length === 0)
\r
3489 * Tests if a definition most likely describes a service.
\r
3490 * @param {!Object} def
\r
3491 * @returns {boolean}
\r
3494 Builder.isService = function(def) {
\r
3495 // Services require a string name and an rpc object
\r
3496 if (typeof def["name"] !== 'string' || typeof def["rpc"] !== 'object' || !def["rpc"])
\r
3502 * Tests if a definition most likely describes an extended message
\r
3503 * @param {!Object} def
\r
3504 * @returns {boolean}
\r
3507 Builder.isExtend = function(def) {
\r
3508 // Extends rquire a string ref
\r
3509 if (typeof def["ref"] !== 'string')
\r
3514 // ----- Building -----
\r
3517 * Resets the pointer to the root namespace.
\r
3518 * @returns {!ProtoBuf.Builder} this
\r
3521 BuilderPrototype.reset = function() {
\r
3522 this.ptr = this.ns;
\r
3527 * Defines a namespace on top of the current pointer position and places the pointer on it.
\r
3528 * @param {string} namespace
\r
3529 * @return {!ProtoBuf.Builder} this
\r
3532 BuilderPrototype.define = function(namespace) {
\r
3533 if (typeof namespace !== 'string' || !Lang.TYPEREF.test(namespace))
\r
3534 throw Error("illegal namespace: "+namespace);
\r
3535 namespace.split(".").forEach(function(part) {
\r
3536 var ns = this.ptr.getChild(part);
\r
3537 if (ns === null) // Keep existing
\r
3538 this.ptr.addChild(ns = new Reflect.Namespace(this, this.ptr, part));
\r
3545 * Creates the specified definitions at the current pointer position.
\r
3546 * @param {!Array.<!Object>} defs Messages, enums or services to create
\r
3547 * @returns {!ProtoBuf.Builder} this
\r
3548 * @throws {Error} If a message definition is invalid
\r
3551 BuilderPrototype.create = function(defs) {
\r
3553 return this; // Nothing to create
\r
3554 if (!Array.isArray(defs))
\r
3557 if (defs.length === 0)
\r
3559 defs = defs.slice();
\r
3562 // It's quite hard to keep track of scopes and memory here, so let's do this iteratively.
\r
3563 var stack = [defs];
\r
3564 while (stack.length > 0) {
\r
3565 defs = stack.pop();
\r
3567 if (!Array.isArray(defs)) // Stack always contains entire namespaces
\r
3568 throw Error("not a valid namespace: "+JSON.stringify(defs));
\r
3570 while (defs.length > 0) {
\r
3571 var def = defs.shift(); // Namespaces always contain an array of messages, enums and services
\r
3573 if (Builder.isMessage(def)) {
\r
3574 var obj = new Reflect.Message(this, this.ptr, def["name"], def["options"], def["isGroup"], def["syntax"]);
\r
3578 if (def["oneofs"])
\r
3579 Object.keys(def["oneofs"]).forEach(function(name) {
\r
3580 obj.addChild(oneofs[name] = new Reflect.Message.OneOf(this, obj, name));
\r
3584 if (def["fields"])
\r
3585 def["fields"].forEach(function(fld) {
\r
3586 if (obj.getChild(fld["id"]|0) !== null)
\r
3587 throw Error("duplicate or invalid field id in "+obj.name+": "+fld['id']);
\r
3588 if (fld["options"] && typeof fld["options"] !== 'object')
\r
3589 throw Error("illegal field options in "+obj.name+"#"+fld["name"]);
\r
3591 if (typeof fld["oneof"] === 'string' && !(oneof = oneofs[fld["oneof"]]))
\r
3592 throw Error("illegal oneof in "+obj.name+"#"+fld["name"]+": "+fld["oneof"]);
\r
3593 fld = new Reflect.Message.Field(this, obj, fld["rule"], fld["keytype"], fld["type"], fld["name"], fld["id"], fld["options"], oneof, def["syntax"]);
\r
3595 oneof.fields.push(fld);
\r
3596 obj.addChild(fld);
\r
3599 // Push children to stack
\r
3602 def["enums"].forEach(function(enm) {
\r
3605 if (def["messages"])
\r
3606 def["messages"].forEach(function(msg) {
\r
3609 if (def["services"])
\r
3610 def["services"].forEach(function(svc) {
\r
3614 // Set extension ranges
\r
3615 if (def["extensions"]) {
\r
3616 if (typeof def["extensions"][0] === 'number') // pre 5.0.1
\r
3617 obj.extensions = [ def["extensions"] ];
\r
3619 obj.extensions = def["extensions"];
\r
3622 // Create on top of current namespace
\r
3623 this.ptr.addChild(obj);
\r
3624 if (subObj.length > 0) {
\r
3625 stack.push(defs); // Push the current level back
\r
3626 defs = subObj; // Continue processing sub level
\r
3628 this.ptr = obj; // And move the pointer to this namespace
\r
3634 } else if (Builder.isEnum(def)) {
\r
3636 obj = new Reflect.Enum(this, this.ptr, def["name"], def["options"], def["syntax"]);
\r
3637 def["values"].forEach(function(val) {
\r
3638 obj.addChild(new Reflect.Enum.Value(this, obj, val["name"], val["id"]));
\r
3640 this.ptr.addChild(obj);
\r
3642 } else if (Builder.isService(def)) {
\r
3644 obj = new Reflect.Service(this, this.ptr, def["name"], def["options"]);
\r
3645 Object.keys(def["rpc"]).forEach(function(name) {
\r
3646 var mtd = def["rpc"][name];
\r
3647 obj.addChild(new Reflect.Service.RPCMethod(this, obj, name, mtd["request"], mtd["response"], !!mtd["request_stream"], !!mtd["response_stream"], mtd["options"]));
\r
3649 this.ptr.addChild(obj);
\r
3651 } else if (Builder.isExtend(def)) {
\r
3653 obj = this.ptr.resolve(def["ref"], true);
\r
3655 def["fields"].forEach(function(fld) {
\r
3656 if (obj.getChild(fld['id']|0) !== null)
\r
3657 throw Error("duplicate extended field id in "+obj.name+": "+fld['id']);
\r
3658 // Check if field id is allowed to be extended
\r
3659 if (obj.extensions) {
\r
3660 var valid = false;
\r
3661 obj.extensions.forEach(function(range) {
\r
3662 if (fld["id"] >= range[0] && fld["id"] <= range[1])
\r
3666 throw Error("illegal extended field id in "+obj.name+": "+fld['id']+" (not within valid ranges)");
\r
3668 // Convert extension field names to camel case notation if the override is set
\r
3669 var name = fld["name"];
\r
3670 if (this.options['convertFieldsToCamelCase'])
\r
3671 name = ProtoBuf.Util.toCamelCase(name);
\r
3672 // see #161: Extensions use their fully qualified name as their runtime key and...
\r
3673 var field = new Reflect.Message.ExtensionField(this, obj, fld["rule"], fld["type"], this.ptr.fqn()+'.'+name, fld["id"], fld["options"]);
\r
3674 // ...are added on top of the current namespace as an extension which is used for
\r
3675 // resolving their type later on (the extension always keeps the original name to
\r
3676 // prevent naming collisions)
\r
3677 var ext = new Reflect.Extension(this, this.ptr, fld["name"], field);
\r
3678 field.extension = ext;
\r
3679 this.ptr.addChild(ext);
\r
3680 obj.addChild(field);
\r
3683 } else if (!/\.?google\.protobuf\./.test(def["ref"])) // Silently skip internal extensions
\r
3684 throw Error("extended message "+def["ref"]+" is not defined");
\r
3687 throw Error("not a valid definition: "+JSON.stringify(def));
\r
3692 // Break goes here
\r
3694 this.ptr = this.ptr.parent; // Namespace done, continue at parent
\r
3696 this.resolved = false; // Require re-resolve
\r
3697 this.result = null; // Require re-build
\r
3702 * Propagates syntax to all children.
\r
3703 * @param {!Object} parent
\r
3706 function propagateSyntax(parent) {
\r
3707 if (parent['messages']) {
\r
3708 parent['messages'].forEach(function(child) {
\r
3709 child["syntax"] = parent["syntax"];
\r
3710 propagateSyntax(child);
\r
3713 if (parent['enums']) {
\r
3714 parent['enums'].forEach(function(child) {
\r
3715 child["syntax"] = parent["syntax"];
\r
3721 * Imports another definition into this builder.
\r
3722 * @param {Object.<string,*>} json Parsed import
\r
3723 * @param {(string|{root: string, file: string})=} filename Imported file name
\r
3724 * @returns {!ProtoBuf.Builder} this
\r
3725 * @throws {Error} If the definition or file cannot be imported
\r
3728 BuilderPrototype["import"] = function(json, filename) {
\r
3731 // Make sure to skip duplicate imports
\r
3733 if (typeof filename === 'string') {
\r
3735 if (ProtoBuf.Util.IS_NODE)
\r
3736 filename = require("path")['resolve'](filename);
\r
3737 if (this.files[filename] === true)
\r
3738 return this.reset();
\r
3739 this.files[filename] = true;
\r
3741 } else if (typeof filename === 'object') { // Object with root, file.
\r
3743 var root = filename.root;
\r
3744 if (ProtoBuf.Util.IS_NODE)
\r
3745 root = require("path")['resolve'](root);
\r
3746 if (root.indexOf("\\") >= 0 || filename.file.indexOf("\\") >= 0)
\r
3749 if (ProtoBuf.Util.IS_NODE)
\r
3750 fname = require("path")['join'](root, filename.file);
\r
3752 fname = root + delim + filename.file;
\r
3753 if (this.files[fname] === true)
\r
3754 return this.reset();
\r
3755 this.files[fname] = true;
\r
3760 if (json['imports'] && json['imports'].length > 0) {
\r
3762 resetRoot = false;
\r
3764 if (typeof filename === 'object') { // If an import root is specified, override
\r
3766 this.importRoot = filename["root"]; resetRoot = true; // ... and reset afterwards
\r
3767 importRoot = this.importRoot;
\r
3768 filename = filename["file"];
\r
3769 if (importRoot.indexOf("\\") >= 0 || filename.indexOf("\\") >= 0)
\r
3772 } else if (typeof filename === 'string') {
\r
3774 if (this.importRoot) // If import root is overridden, use it
\r
3775 importRoot = this.importRoot;
\r
3776 else { // Otherwise compute from filename
\r
3777 if (filename.indexOf("/") >= 0) { // Unix
\r
3778 importRoot = filename.replace(/\/[^\/]*$/, "");
\r
3779 if (/* /file.proto */ importRoot === "")
\r
3781 } else if (filename.indexOf("\\") >= 0) { // Windows
\r
3782 importRoot = filename.replace(/\\[^\\]*$/, "");
\r
3789 importRoot = null;
\r
3791 for (var i=0; i<json['imports'].length; i++) {
\r
3792 if (typeof json['imports'][i] === 'string') { // Import file
\r
3794 throw Error("cannot determine import root");
\r
3795 var importFilename = json['imports'][i];
\r
3796 if (importFilename === "google/protobuf/descriptor.proto")
\r
3797 continue; // Not needed and therefore not used
\r
3798 if (ProtoBuf.Util.IS_NODE)
\r
3799 importFilename = require("path")['join'](importRoot, importFilename);
\r
3801 importFilename = importRoot + delim + importFilename;
\r
3802 if (this.files[importFilename] === true)
\r
3803 continue; // Already imported
\r
3804 if (/\.proto$/i.test(importFilename) && !ProtoBuf.DotProto) // If this is a light build
\r
3805 importFilename = importFilename.replace(/\.proto$/, ".json"); // always load the JSON file
\r
3806 var contents = ProtoBuf.Util.fetch(importFilename);
\r
3807 if (contents === null)
\r
3808 throw Error("failed to import '"+importFilename+"' in '"+filename+"': file not found");
\r
3809 if (/\.json$/i.test(importFilename)) // Always possible
\r
3810 this["import"](JSON.parse(contents+""), importFilename); // May throw
\r
3812 this["import"](ProtoBuf.DotProto.Parser.parse(contents), importFilename); // May throw
\r
3813 } else // Import structure
\r
3815 this["import"](json['imports'][i]);
\r
3816 else if (/\.(\w+)$/.test(filename)) // With extension: Append _importN to the name portion to make it unique
\r
3817 this["import"](json['imports'][i], filename.replace(/^(.+)\.(\w+)$/, function($0, $1, $2) { return $1+"_import"+i+"."+$2; }));
\r
3818 else // Without extension: Append _importN to make it unique
\r
3819 this["import"](json['imports'][i], filename+"_import"+i);
\r
3821 if (resetRoot) // Reset import root override when all imports are done
\r
3822 this.importRoot = null;
\r
3825 // Import structures
\r
3827 if (json['package'])
\r
3828 this.define(json['package']);
\r
3829 if (json['syntax'])
\r
3830 propagateSyntax(json);
\r
3831 var base = this.ptr;
\r
3832 if (json['options'])
\r
3833 Object.keys(json['options']).forEach(function(key) {
\r
3834 base.options[key] = json['options'][key];
\r
3836 if (json['messages'])
\r
3837 this.create(json['messages']),
\r
3839 if (json['enums'])
\r
3840 this.create(json['enums']),
\r
3842 if (json['services'])
\r
3843 this.create(json['services']),
\r
3845 if (json['extends'])
\r
3846 this.create(json['extends']);
\r
3848 return this.reset();
\r
3852 * Resolves all namespace objects.
\r
3853 * @throws {Error} If a type cannot be resolved
\r
3854 * @returns {!ProtoBuf.Builder} this
\r
3857 BuilderPrototype.resolveAll = function() {
\r
3858 // Resolve all reflected objects
\r
3860 if (this.ptr == null || typeof this.ptr.type === 'object')
\r
3861 return this; // Done (already resolved)
\r
3863 if (this.ptr instanceof Reflect.Namespace) { // Resolve children
\r
3865 this.ptr.children.forEach(function(child) {
\r
3867 this.resolveAll();
\r
3870 } else if (this.ptr instanceof Reflect.Message.Field) { // Resolve type
\r
3872 if (!Lang.TYPE.test(this.ptr.type)) {
\r
3873 if (!Lang.TYPEREF.test(this.ptr.type))
\r
3874 throw Error("illegal type reference in "+this.ptr.toString(true)+": "+this.ptr.type);
\r
3875 res = (this.ptr instanceof Reflect.Message.ExtensionField ? this.ptr.extension.parent : this.ptr.parent).resolve(this.ptr.type, true);
\r
3877 throw Error("unresolvable type reference in "+this.ptr.toString(true)+": "+this.ptr.type);
\r
3878 this.ptr.resolvedType = res;
\r
3879 if (res instanceof Reflect.Enum) {
\r
3880 this.ptr.type = ProtoBuf.TYPES["enum"];
\r
3881 if (this.ptr.syntax === 'proto3' && res.syntax !== 'proto3')
\r
3882 throw Error("proto3 message cannot reference proto2 enum");
\r
3884 else if (res instanceof Reflect.Message)
\r
3885 this.ptr.type = res.isGroup ? ProtoBuf.TYPES["group"] : ProtoBuf.TYPES["message"];
\r
3887 throw Error("illegal type reference in "+this.ptr.toString(true)+": "+this.ptr.type);
\r
3889 this.ptr.type = ProtoBuf.TYPES[this.ptr.type];
\r
3891 // If it's a map field, also resolve the key type. The key type can be only a numeric, string, or bool type
\r
3892 // (i.e., no enums or messages), so we don't need to resolve against the current namespace.
\r
3893 if (this.ptr.map) {
\r
3894 if (!Lang.TYPE.test(this.ptr.keyType))
\r
3895 throw Error("illegal key type for map field in "+this.ptr.toString(true)+": "+this.ptr.keyType);
\r
3896 this.ptr.keyType = ProtoBuf.TYPES[this.ptr.keyType];
\r
3899 // If it's a repeated and packable field then proto3 mandates it should be packed by
\r
3902 this.ptr.syntax === 'proto3' &&
\r
3903 this.ptr.repeated && this.ptr.options.packed === undefined &&
\r
3904 ProtoBuf.PACKABLE_WIRE_TYPES.indexOf(this.ptr.type.wireType) !== -1
\r
3906 this.ptr.options.packed = true;
\r
3909 } else if (this.ptr instanceof ProtoBuf.Reflect.Service.Method) {
\r
3911 if (this.ptr instanceof ProtoBuf.Reflect.Service.RPCMethod) {
\r
3912 res = this.ptr.parent.resolve(this.ptr.requestName, true);
\r
3913 if (!res || !(res instanceof ProtoBuf.Reflect.Message))
\r
3914 throw Error("Illegal type reference in "+this.ptr.toString(true)+": "+this.ptr.requestName);
\r
3915 this.ptr.resolvedRequestType = res;
\r
3916 res = this.ptr.parent.resolve(this.ptr.responseName, true);
\r
3917 if (!res || !(res instanceof ProtoBuf.Reflect.Message))
\r
3918 throw Error("Illegal type reference in "+this.ptr.toString(true)+": "+this.ptr.responseName);
\r
3919 this.ptr.resolvedResponseType = res;
\r
3920 } else // Should not happen as nothing else is implemented
\r
3921 throw Error("illegal service type in "+this.ptr.toString(true));
\r
3924 !(this.ptr instanceof ProtoBuf.Reflect.Message.OneOf) && // Not built
\r
3925 !(this.ptr instanceof ProtoBuf.Reflect.Extension) && // Not built
\r
3926 !(this.ptr instanceof ProtoBuf.Reflect.Enum.Value) // Built in enum
\r
3928 throw Error("illegal object in namespace: "+typeof(this.ptr)+": "+this.ptr);
\r
3930 return this.reset();
\r
3934 * Builds the protocol. This will first try to resolve all definitions and, if this has been successful,
\r
3935 * return the built package.
\r
3936 * @param {(string|Array.<string>)=} path Specifies what to return. If omitted, the entire namespace will be returned.
\r
3937 * @returns {!ProtoBuf.Builder.Message|!Object.<string,*>}
\r
3938 * @throws {Error} If a type could not be resolved
\r
3941 BuilderPrototype.build = function(path) {
\r
3943 if (!this.resolved)
\r
3944 this.resolveAll(),
\r
3945 this.resolved = true,
\r
3946 this.result = null; // Require re-build
\r
3947 if (this.result === null) // (Re-)Build
\r
3948 this.result = this.ns.build();
\r
3950 return this.result;
\r
3951 var part = typeof path === 'string' ? path.split(".") : path,
\r
3952 ptr = this.result; // Build namespace pointer (no hasChild etc.)
\r
3953 for (var i=0; i<part.length; i++)
\r
3955 ptr = ptr[part[i]];
\r
3964 * Similar to {@link ProtoBuf.Builder#build}, but looks up the internal reflection descriptor.
\r
3965 * @param {string=} path Specifies what to return. If omitted, the entire namespace wiil be returned.
\r
3966 * @param {boolean=} excludeNonNamespace Excludes non-namespace types like fields, defaults to `false`
\r
3967 * @returns {?ProtoBuf.Reflect.T} Reflection descriptor or `null` if not found
\r
3969 BuilderPrototype.lookup = function(path, excludeNonNamespace) {
\r
3970 return path ? this.ns.resolve(path, excludeNonNamespace) : this.ns;
\r
3974 * Returns a string representation of this object.
\r
3975 * @return {string} String representation as of "Builder"
\r
3978 BuilderPrototype.toString = function() {
\r
3982 // ----- Base classes -----
\r
3983 // Exist for the sole purpose of being able to "... instanceof ProtoBuf.Builder.Message" etc.
\r
3986 * @alias ProtoBuf.Builder.Message
\r
3988 Builder.Message = function() {};
\r
3991 * @alias ProtoBuf.Builder.Enum
\r
3993 Builder.Enum = function() {};
\r
3996 * @alias ProtoBuf.Builder.Message
\r
3998 Builder.Service = function() {};
\r
4002 })(ProtoBuf, ProtoBuf.Lang, ProtoBuf.Reflect);
\r
4005 * @alias ProtoBuf.Map
\r
4008 ProtoBuf.Map = (function(ProtoBuf, Reflect) {
\r
4012 * Constructs a new Map. A Map is a container that is used to implement map
\r
4013 * fields on message objects. It closely follows the ES6 Map API; however,
\r
4014 * it is distinct because we do not want to depend on external polyfills or
\r
4017 * @exports ProtoBuf.Map
\r
4018 * @param {!ProtoBuf.Reflect.Field} field Map field
\r
4019 * @param {Object.<string,*>=} contents Initial contents
\r
4022 var Map = function(field, contents) {
\r
4024 throw Error("field is not a map");
\r
4027 * The field corresponding to this map.
\r
4028 * @type {!ProtoBuf.Reflect.Field}
\r
4030 this.field = field;
\r
4033 * Element instance corresponding to key type.
\r
4034 * @type {!ProtoBuf.Reflect.Element}
\r
4036 this.keyElem = new Reflect.Element(field.keyType, null, true, field.syntax);
\r
4039 * Element instance corresponding to value type.
\r
4040 * @type {!ProtoBuf.Reflect.Element}
\r
4042 this.valueElem = new Reflect.Element(field.type, field.resolvedType, false, field.syntax);
\r
4045 * Internal map: stores mapping of (string form of key) -> (key, value)
\r
4048 * We provide map semantics for arbitrary key types, but we build on top
\r
4049 * of an Object, which has only string keys. In order to avoid the need
\r
4050 * to convert a string key back to its native type in many situations,
\r
4051 * we store the native key value alongside the value. Thus, we only need
\r
4052 * a one-way mapping from a key type to its string form that guarantees
\r
4053 * uniqueness and equality (i.e., str(K1) === str(K2) if and only if K1
\r
4056 * @type {!Object<string, {key: *, value: *}>}
\r
4061 * Returns the number of elements in the map.
\r
4063 Object.defineProperty(this, "size", {
\r
4064 get: function() { return Object.keys(this.map).length; }
\r
4067 // Fill initial contents from a raw object.
\r
4069 var keys = Object.keys(contents);
\r
4070 for (var i = 0; i < keys.length; i++) {
\r
4071 var key = this.keyElem.valueFromString(keys[i]);
\r
4072 var val = this.valueElem.verifyValue(contents[keys[i]]);
\r
4073 this.map[this.keyElem.valueToString(key)] =
\r
4074 { key: key, value: val };
\r
4079 var MapPrototype = Map.prototype;
\r
4082 * Helper: return an iterator over an array.
\r
4083 * @param {!Array<*>} arr the array
\r
4084 * @returns {!Object} an iterator
\r
4087 function arrayIterator(arr) {
\r
4090 next: function() {
\r
4091 if (idx < arr.length)
\r
4092 return { done: false, value: arr[idx++] };
\r
4093 return { done: true };
\r
4101 MapPrototype.clear = function() {
\r
4106 * Deletes a particular key from the map.
\r
4107 * @returns {boolean} Whether any entry with this key was deleted.
\r
4109 MapPrototype["delete"] = function(key) {
\r
4110 var keyValue = this.keyElem.valueToString(this.keyElem.verifyValue(key));
\r
4111 var hadKey = keyValue in this.map;
\r
4112 delete this.map[keyValue];
\r
4117 * Returns an iterator over [key, value] pairs in the map.
\r
4118 * @returns {Object} The iterator
\r
4120 MapPrototype.entries = function() {
\r
4122 var strKeys = Object.keys(this.map);
\r
4123 for (var i = 0, entry; i < strKeys.length; i++)
\r
4124 entries.push([(entry=this.map[strKeys[i]]).key, entry.value]);
\r
4125 return arrayIterator(entries);
\r
4129 * Returns an iterator over keys in the map.
\r
4130 * @returns {Object} The iterator
\r
4132 MapPrototype.keys = function() {
\r
4134 var strKeys = Object.keys(this.map);
\r
4135 for (var i = 0; i < strKeys.length; i++)
\r
4136 keys.push(this.map[strKeys[i]].key);
\r
4137 return arrayIterator(keys);
\r
4141 * Returns an iterator over values in the map.
\r
4142 * @returns {!Object} The iterator
\r
4144 MapPrototype.values = function() {
\r
4146 var strKeys = Object.keys(this.map);
\r
4147 for (var i = 0; i < strKeys.length; i++)
\r
4148 values.push(this.map[strKeys[i]].value);
\r
4149 return arrayIterator(values);
\r
4153 * Iterates over entries in the map, calling a function on each.
\r
4154 * @param {function(this:*, *, *, *)} cb The callback to invoke with value, key, and map arguments.
\r
4155 * @param {Object=} thisArg The `this` value for the callback
\r
4157 MapPrototype.forEach = function(cb, thisArg) {
\r
4158 var strKeys = Object.keys(this.map);
\r
4159 for (var i = 0, entry; i < strKeys.length; i++)
\r
4160 cb.call(thisArg, (entry=this.map[strKeys[i]]).value, entry.key, this);
\r
4164 * Sets a key in the map to the given value.
\r
4165 * @param {*} key The key
\r
4166 * @param {*} value The value
\r
4167 * @returns {!ProtoBuf.Map} The map instance
\r
4169 MapPrototype.set = function(key, value) {
\r
4170 var keyValue = this.keyElem.verifyValue(key);
\r
4171 var valValue = this.valueElem.verifyValue(value);
\r
4172 this.map[this.keyElem.valueToString(keyValue)] =
\r
4173 { key: keyValue, value: valValue };
\r
4178 * Gets the value corresponding to a key in the map.
\r
4179 * @param {*} key The key
\r
4180 * @returns {*|undefined} The value, or `undefined` if key not present
\r
4182 MapPrototype.get = function(key) {
\r
4183 var keyValue = this.keyElem.valueToString(this.keyElem.verifyValue(key));
\r
4184 if (!(keyValue in this.map))
\r
4186 return this.map[keyValue].value;
\r
4190 * Determines whether the given key is present in the map.
\r
4191 * @param {*} key The key
\r
4192 * @returns {boolean} `true` if the key is present
\r
4194 MapPrototype.has = function(key) {
\r
4195 var keyValue = this.keyElem.valueToString(this.keyElem.verifyValue(key));
\r
4196 return (keyValue in this.map);
\r
4200 })(ProtoBuf, ProtoBuf.Reflect);
\r
4204 * Constructs a new empty Builder.
\r
4205 * @param {Object.<string,*>=} options Builder options, defaults to global options set on ProtoBuf
\r
4206 * @return {!ProtoBuf.Builder} Builder
\r
4209 ProtoBuf.newBuilder = function(options) {
\r
4210 options = options || {};
\r
4211 if (typeof options['convertFieldsToCamelCase'] === 'undefined')
\r
4212 options['convertFieldsToCamelCase'] = ProtoBuf.convertFieldsToCamelCase;
\r
4213 if (typeof options['populateAccessors'] === 'undefined')
\r
4214 options['populateAccessors'] = ProtoBuf.populateAccessors;
\r
4215 return new ProtoBuf.Builder(options);
\r
4219 * Loads a .json definition and returns the Builder.
\r
4220 * @param {!*|string} json JSON definition
\r
4221 * @param {(ProtoBuf.Builder|string|{root: string, file: string})=} builder Builder to append to. Will create a new one if omitted.
\r
4222 * @param {(string|{root: string, file: string})=} filename The corresponding file name if known. Must be specified for imports.
\r
4223 * @return {ProtoBuf.Builder} Builder to create new messages
\r
4224 * @throws {Error} If the definition cannot be parsed or built
\r
4227 ProtoBuf.loadJson = function(json, builder, filename) {
\r
4228 if (typeof builder === 'string' || (builder && typeof builder["file"] === 'string' && typeof builder["root"] === 'string'))
\r
4229 filename = builder,
\r
4231 if (!builder || typeof builder !== 'object')
\r
4232 builder = ProtoBuf.newBuilder();
\r
4233 if (typeof json === 'string')
\r
4234 json = JSON.parse(json);
\r
4235 builder["import"](json, filename);
\r
4236 builder.resolveAll();
\r
4241 * Loads a .json file and returns the Builder.
\r
4242 * @param {string|!{root: string, file: string}} filename Path to json file or an object specifying 'file' with
\r
4243 * an overridden 'root' path for all imported files.
\r
4244 * @param {function(?Error, !ProtoBuf.Builder=)=} callback Callback that will receive `null` as the first and
\r
4245 * the Builder as its second argument on success, otherwise the error as its first argument. If omitted, the
\r
4246 * file will be read synchronously and this function will return the Builder.
\r
4247 * @param {ProtoBuf.Builder=} builder Builder to append to. Will create a new one if omitted.
\r
4248 * @return {?ProtoBuf.Builder|undefined} The Builder if synchronous (no callback specified, will be NULL if the
\r
4249 * request has failed), else undefined
\r
4252 ProtoBuf.loadJsonFile = function(filename, callback, builder) {
\r
4253 if (callback && typeof callback === 'object')
\r
4254 builder = callback,
\r
4256 else if (!callback || typeof callback !== 'function')
\r
4259 return ProtoBuf.Util.fetch(typeof filename === 'string' ? filename : filename["root"]+"/"+filename["file"], function(contents) {
\r
4260 if (contents === null) {
\r
4261 callback(Error("Failed to fetch file"));
\r
4265 callback(null, ProtoBuf.loadJson(JSON.parse(contents), builder, filename));
\r
4270 var contents = ProtoBuf.Util.fetch(typeof filename === 'object' ? filename["root"]+"/"+filename["file"] : filename);
\r
4271 return contents === null ? null : ProtoBuf.loadJson(JSON.parse(contents), builder, filename);
\r