protobufjs 5.0.0 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/bower.json +1 -1
  2. package/cli/pbjs/targets/json.js +1 -1
  3. package/cli/pbjs/targets/proto.js +10 -2
  4. package/dist/protobuf-light.js +38 -21
  5. package/dist/protobuf-light.min.js +78 -78
  6. package/dist/protobuf-light.min.js.gz +0 -0
  7. package/dist/protobuf-light.min.map +2 -2
  8. package/dist/protobuf.js +81 -55
  9. package/dist/protobuf.min.js +92 -92
  10. package/dist/protobuf.min.js.gz +0 -0
  11. package/dist/protobuf.min.map +2 -2
  12. package/docs/ProtoBuf.Builder.Message.html +106 -37
  13. package/docs/ProtoBuf.Builder.Service.html +9 -9
  14. package/docs/ProtoBuf.Builder.html +22 -22
  15. package/docs/ProtoBuf.DotProto.Parser.html +3 -3
  16. package/docs/ProtoBuf.DotProto.Tokenizer.html +1 -1
  17. package/docs/ProtoBuf.DotProto.html +1 -1
  18. package/docs/ProtoBuf.Map.html +6 -6
  19. package/docs/ProtoBuf.Reflect.Element.html +7 -7
  20. package/docs/ProtoBuf.Reflect.Enum.Value.html +10 -10
  21. package/docs/ProtoBuf.Reflect.Enum.html +21 -21
  22. package/docs/ProtoBuf.Reflect.Extension.html +3 -3
  23. package/docs/ProtoBuf.Reflect.Message.ExtensionField.html +29 -29
  24. package/docs/ProtoBuf.Reflect.Message.Field.html +28 -28
  25. package/docs/ProtoBuf.Reflect.Message.OneOf.html +10 -10
  26. package/docs/ProtoBuf.Reflect.Message.html +31 -28
  27. package/docs/ProtoBuf.Reflect.Namespace.html +19 -19
  28. package/docs/ProtoBuf.Reflect.Service.Method.html +11 -11
  29. package/docs/ProtoBuf.Reflect.Service.RPCMethod.html +17 -17
  30. package/docs/ProtoBuf.Reflect.Service.html +20 -20
  31. package/docs/ProtoBuf.Reflect.T.html +9 -9
  32. package/docs/ProtoBuf.Reflect.html +2 -2
  33. package/docs/ProtoBuf.Util.html +1 -1
  34. package/docs/ProtoBuf.html +8 -8
  35. package/docs/ProtoBuf.js.html +82 -56
  36. package/docs/index.html +1 -1
  37. package/externs/protobuf.js +2 -1
  38. package/package.json +1 -1
  39. package/src/ProtoBuf/Builder/Message.js +8 -3
  40. package/src/ProtoBuf/Builder/Service.js +3 -0
  41. package/src/ProtoBuf/Builder.js +15 -8
  42. package/src/ProtoBuf/DotProto/Parser.js +43 -34
  43. package/src/ProtoBuf/Reflect/Element.js +4 -3
  44. package/src/ProtoBuf/Reflect/Message/Field.js +4 -3
  45. package/src/ProtoBuf/Reflect/Message.js +3 -3
  46. package/src/google/protobuf/descriptor.json +28 -14
  47. package/tests/imports-weak.proto +7 -0
  48. package/tests/suite.js +63 -83
  49. package/tests/gtfs-realtime.proto +0 -552
@@ -84,7 +84,7 @@
84
84
  * @const
85
85
  * @expose
86
86
  */
87
- ProtoBuf.VERSION = "5.0.0";
87
+ ProtoBuf.VERSION = "5.0.1";
88
88
 
89
89
  /**
90
90
  * Wire types.
@@ -752,7 +752,8 @@
752
752
  // "syntax": undefined
753
753
  };
754
754
  var token,
755
- head = true;
755
+ head = true,
756
+ weak;
756
757
  try {
757
758
  while (token = this.tn.next()) {
758
759
  switch (token) {
@@ -769,11 +770,12 @@
769
770
  if (!head)
770
771
  throw Error("unexpected 'import'");
771
772
  token = this.tn.peek();
772
- if (token === "public") // ignored
773
+ if (token === "public" || (weak = token === "weak")) // token ignored
773
774
  this.tn.next();
774
775
  token = this._readString();
775
776
  this.tn.skip(";");
776
- topLevel["imports"].push(token);
777
+ if (!weak) // import ignored
778
+ topLevel["imports"].push(token);
777
779
  break;
778
780
  case 'syntax':
779
781
  if (!head)
@@ -1128,11 +1130,11 @@
1128
1130
  else if (token === "service")
1129
1131
  this._parseService(msg);
1130
1132
  else if (token === "extensions")
1131
- this._parseExtensions(msg);
1133
+ msg["extensions"] = this._parseExtensionRanges();
1134
+ else if (token === "reserved")
1135
+ this._parseIgnored(); // TODO
1132
1136
  else if (token === "extend")
1133
1137
  this._parseExtend(msg);
1134
- else if (token === "reserved")
1135
- this._parseMessageReserved(msg);
1136
1138
  else if (Lang.TYPEREF.test(token)) {
1137
1139
  if (!this.proto3)
1138
1140
  throw Error("illegal field rule: "+token);
@@ -1146,17 +1148,10 @@
1146
1148
  };
1147
1149
 
1148
1150
  /**
1149
- * Parses a message's reserved ids / names statement.
1150
- * @param {!Object} msg Message definition
1151
+ * Parses an ignored statement.
1151
1152
  * @private
1152
1153
  */
1153
- ParserPrototype._parseMessageReserved = function(msg) {
1154
- // TODO: This currently just skips a reserved statement for compatibility.
1155
- // Valid formats are
1156
- // reserved 2, 15, 9 to 11;
1157
- // for reserved ids or
1158
- // reserved "foo", "bar";
1159
- // for reserved names.
1154
+ ParserPrototype._parseIgnored = function() {
1160
1155
  while (this.tn.peek() !== ';')
1161
1156
  this.tn.next();
1162
1157
  this.tn.skip(";");
@@ -1324,29 +1319,43 @@
1324
1319
  };
1325
1320
 
1326
1321
  /**
1327
- * Parses an extensions statement.
1328
- * @param {!Object} msg Message object
1322
+ * Parses extension / reserved ranges.
1323
+ * @returns {!Array.<!Array.<number>>}
1329
1324
  * @private
1330
1325
  */
1331
- ParserPrototype._parseExtensions = function(msg) {
1332
- var token = this.tn.next(),
1326
+ ParserPrototype._parseExtensionRanges = function() {
1327
+ var ranges = [];
1328
+ var token,
1329
+ range,
1330
+ value;
1331
+ do {
1333
1332
  range = [];
1334
- if (token === "min")
1335
- range.push(ProtoBuf.ID_MIN);
1336
- else if (token === "max")
1337
- range.push(ProtoBuf.ID_MAX);
1338
- else
1339
- range.push(mkNumber(token));
1340
- this.tn.skip("to");
1341
- token = this.tn.next();
1342
- if (token === "min")
1343
- range.push(ProtoBuf.ID_MIN);
1344
- else if (token === "max")
1345
- range.push(ProtoBuf.ID_MAX);
1346
- else
1347
- range.push(mkNumber(token));
1333
+ while (true) {
1334
+ token = this.tn.next();
1335
+ switch (token) {
1336
+ case "min":
1337
+ value = ProtoBuf.ID_MIN;
1338
+ break;
1339
+ case "max":
1340
+ value = ProtoBuf.ID_MAX;
1341
+ break;
1342
+ default:
1343
+ value = mkNumber(token);
1344
+ break;
1345
+ }
1346
+ range.push(value);
1347
+ if (range.length === 2)
1348
+ break;
1349
+ if (this.tn.peek() !== "to") {
1350
+ range.push(value);
1351
+ break;
1352
+ }
1353
+ this.tn.next();
1354
+ }
1355
+ ranges.push(range);
1356
+ } while (this.tn.omit(","));
1348
1357
  this.tn.skip(";");
1349
- msg["extensions"] = range;
1358
+ return ranges;
1350
1359
  };
1351
1360
 
1352
1361
  /**
@@ -1814,9 +1823,10 @@
1814
1823
  * @expose
1815
1824
  */
1816
1825
  ElementPrototype.verifyValue = function(value) {
1817
- var fail = function(val, msg) {
1818
- throw Error("Illegal value for "+this.toString(true)+" of type "+this.type.name+": "+val+" ("+msg+")");
1819
- }.bind(this);
1826
+ var self = this;
1827
+ function fail(val, msg) {
1828
+ throw Error("Illegal value for "+self.toString(true)+" of type "+self.type.name+": "+val+" ("+msg+")");
1829
+ }
1820
1830
  switch (this.type) {
1821
1831
  // Signed 32bit
1822
1832
  case ProtoBuf.TYPES["int32"]:
@@ -2306,10 +2316,10 @@
2306
2316
 
2307
2317
  /**
2308
2318
  * Extensions range.
2309
- * @type {!Array.<number>}
2319
+ * @type {!Array.<number>|undefined}
2310
2320
  * @expose
2311
2321
  */
2312
- this.extensions = [ProtoBuf.ID_MIN, ProtoBuf.ID_MAX];
2322
+ this.extensions = undefined;
2313
2323
 
2314
2324
  /**
2315
2325
  * Runtime message class.
@@ -2708,18 +2718,19 @@
2708
2718
  * @name ProtoBuf.Builder.Message#encodeDelimited
2709
2719
  * @function
2710
2720
  * @param {(!ByteBuffer|boolean)=} buffer ByteBuffer to encode to. Will create a new one and flip it if omitted.
2721
+ * @param {boolean=} noVerify Whether to not verify field values, defaults to `false`
2711
2722
  * @return {!ByteBuffer} Encoded message as a ByteBuffer
2712
2723
  * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
2713
2724
  * returns the encoded ByteBuffer in the `encoded` property on the error.
2714
2725
  * @expose
2715
2726
  */
2716
- MessagePrototype.encodeDelimited = function(buffer) {
2727
+ MessagePrototype.encodeDelimited = function(buffer, noVerify) {
2717
2728
  var isNew = false;
2718
2729
  if (!buffer)
2719
2730
  buffer = new ByteBuffer(),
2720
2731
  isNew = true;
2721
2732
  var enc = new ByteBuffer().LE();
2722
- T.encode(this, enc).flip();
2733
+ T.encode(this, enc, noVerify).flip();
2723
2734
  buffer.writeVarint32(enc.remaining());
2724
2735
  buffer.append(enc);
2725
2736
  return isNew ? buffer.flip() : buffer;
@@ -2928,6 +2939,7 @@
2928
2939
  * @name ProtoBuf.Builder.Message.decode
2929
2940
  * @function
2930
2941
  * @param {!ByteBuffer|!ArrayBuffer|!Buffer|string} buffer Buffer to decode from
2942
+ * @param {(number|string)=} length Message length. Defaults to decode all the remainig data.
2931
2943
  * @param {string=} enc Encoding if buffer is a string: hex, utf8 (not recommended), defaults to base64
2932
2944
  * @return {!ProtoBuf.Builder.Message} Decoded message
2933
2945
  * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still
@@ -2936,7 +2948,10 @@
2936
2948
  * @see ProtoBuf.Builder.Message.decode64
2937
2949
  * @see ProtoBuf.Builder.Message.decodeHex
2938
2950
  */
2939
- Message.decode = function(buffer, enc) {
2951
+ Message.decode = function(buffer, length, enc) {
2952
+ if (typeof length === 'string')
2953
+ enc = length,
2954
+ length = -1;
2940
2955
  if (typeof buffer === 'string')
2941
2956
  buffer = ByteBuffer.wrap(buffer, enc ? enc : "base64");
2942
2957
  buffer = ByteBuffer.isByteBuffer(buffer) ? buffer : ByteBuffer.wrap(buffer); // May throw
@@ -3197,7 +3212,7 @@
3197
3212
  /**
3198
3213
  * Decodes an encoded message and returns the decoded message.
3199
3214
  * @param {ByteBuffer} buffer ByteBuffer to decode from
3200
- * @param {number=} length Message length. Defaults to decode all the available data.
3215
+ * @param {number=} length Message length. Defaults to decode all remaining data.
3201
3216
  * @param {number=} expectedGroupEndId Expected GROUPEND id if this is a legacy group
3202
3217
  * @return {ProtoBuf.Builder.Message} Decoded message
3203
3218
  * @throws {Error} If the message cannot be decoded
@@ -3447,9 +3462,10 @@
3447
3462
  */
3448
3463
  FieldPrototype.verifyValue = function(value, skipRepeated) {
3449
3464
  skipRepeated = skipRepeated || false;
3450
- var fail = function(val, msg) {
3451
- throw Error("Illegal value for "+this.toString(true)+" of type "+this.type.name+": "+val+" ("+msg+")");
3452
- }.bind(this);
3465
+ var self = this;
3466
+ function fail(val, msg) {
3467
+ throw Error("Illegal value for "+self.toString(true)+" of type "+self.type.name+": "+val+" ("+msg+")");
3468
+ }
3453
3469
  if (value === null) { // NULL values for optional fields
3454
3470
  if (this.required)
3455
3471
  fail(typeof value, "required");
@@ -4063,6 +4079,9 @@
4063
4079
  callback(err);
4064
4080
  return;
4065
4081
  }
4082
+ // Coalesce to empty string when service response has empty content
4083
+ if (res === null)
4084
+ res = ''
4066
4085
  try { res = method.resolvedResponseType.clazz.decode(res); } catch (notABuffer) {}
4067
4086
  if (!res || !(res instanceof method.resolvedResponseType.clazz)) {
4068
4087
  callback(Error("Illegal response type received in service method "+ T.name+"#"+method.name));
@@ -4506,13 +4525,12 @@
4506
4525
  subObj.push(svc);
4507
4526
  });
4508
4527
 
4509
- // Set extension range
4528
+ // Set extension ranges
4510
4529
  if (def["extensions"]) {
4511
- obj.extensions = def["extensions"];
4512
- if (obj.extensions[0] < ProtoBuf.ID_MIN)
4513
- obj.extensions[0] = ProtoBuf.ID_MIN;
4514
- if (obj.extensions[1] > ProtoBuf.ID_MAX)
4515
- obj.extensions[1] = ProtoBuf.ID_MAX;
4530
+ if (typeof def["extensions"][0] === 'number') // pre 5.0.1
4531
+ obj.extensions = [ def["extensions"] ];
4532
+ else
4533
+ obj.extensions = def["extensions"];
4516
4534
  }
4517
4535
 
4518
4536
  // Create on top of current namespace
@@ -4551,8 +4569,16 @@
4551
4569
  def["fields"].forEach(function(fld) {
4552
4570
  if (obj.getChild(fld['id']|0) !== null)
4553
4571
  throw Error("duplicate extended field id in "+obj.name+": "+fld['id']);
4554
- if (fld['id'] < obj.extensions[0] || fld['id'] > obj.extensions[1])
4555
- throw Error("illegal extended field id in "+obj.name+": "+fld['id']+" ("+obj.extensions.join(' to ')+" expected)");
4572
+ // Check if field id is allowed to be extended
4573
+ if (obj.extensions) {
4574
+ var valid = false;
4575
+ obj.extensions.forEach(function(range) {
4576
+ if (fld["id"] >= range[0] && fld["id"] <= range[1])
4577
+ valid = true;
4578
+ });
4579
+ if (!valid)
4580
+ throw Error("illegal extended field id in "+obj.name+": "+fld['id']+" (not within valid ranges)");
4581
+ }
4556
4582
  // Convert extension field names to camel case notation if the override is set
4557
4583
  var name = fld["name"];
4558
4584
  if (this.options['convertFieldsToCamelCase'])
@@ -5238,7 +5264,7 @@
5238
5264
  <br clear="both">
5239
5265
 
5240
5266
  <footer>
5241
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.3.0-alpha9</a> on Tue Nov 17 2015 00:07:57 GMT+0100 (Mitteleuropäische Zeit)
5267
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.3.0-alpha9</a> on Wed Jan 06 2016 01:34:58 GMT+0100 (Mitteleuropäische Zeit)
5242
5268
  </footer>
5243
5269
 
5244
5270
  <script> prettyPrint(); </script>
package/docs/index.html CHANGED
@@ -54,7 +54,7 @@
54
54
  <br clear="both">
55
55
 
56
56
  <footer>
57
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.3.0-alpha9</a> on Tue Nov 17 2015 00:07:57 GMT+0100 (Mitteleuropäische Zeit)
57
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.3.0-alpha9</a> on Wed Jan 06 2016 01:34:58 GMT+0100 (Mitteleuropäische Zeit)
58
58
  </footer>
59
59
 
60
60
  <script> prettyPrint(); </script>
@@ -349,10 +349,11 @@ ProtoBuf.Reflect.Message.prototype.calculate = function(message) {};
349
349
  /**
350
350
  * @param {!ProtoBuf.Builder.Message} message
351
351
  * @param {!ByteBuffer} buffer
352
+ * @param {bool} noVerify
352
353
  * @return {!ByteBuffer}
353
354
  * @throws {Error}
354
355
  */
355
- ProtoBuf.Reflect.Message.prototype.encodeDelimited = function(message, buffer) {};
356
+ ProtoBuf.Reflect.Message.prototype.encodeDelimited = function(message, buffer, noVerify) {};
356
357
 
357
358
  /**
358
359
  * @param {!ByteBuffer} buffer
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "protobufjs",
3
- "version": "5.0.0",
3
+ "version": "5.0.1",
4
4
  "description": "Protocol Buffers for JavaScript. Finally.",
5
5
  "author": "Daniel Wirtz <dcode@dcode.io>",
6
6
  "contributors": [
@@ -340,18 +340,19 @@ MessagePrototype.calculate = function() {
340
340
  * @name ProtoBuf.Builder.Message#encodeDelimited
341
341
  * @function
342
342
  * @param {(!ByteBuffer|boolean)=} buffer ByteBuffer to encode to. Will create a new one and flip it if omitted.
343
+ * @param {boolean=} noVerify Whether to not verify field values, defaults to `false`
343
344
  * @return {!ByteBuffer} Encoded message as a ByteBuffer
344
345
  * @throws {Error} If the message cannot be encoded or if required fields are missing. The later still
345
346
  * returns the encoded ByteBuffer in the `encoded` property on the error.
346
347
  * @expose
347
348
  */
348
- MessagePrototype.encodeDelimited = function(buffer) {
349
+ MessagePrototype.encodeDelimited = function(buffer, noVerify) {
349
350
  var isNew = false;
350
351
  if (!buffer)
351
352
  buffer = new ByteBuffer(),
352
353
  isNew = true;
353
354
  var enc = new ByteBuffer().LE();
354
- T.encode(this, enc).flip();
355
+ T.encode(this, enc, noVerify).flip();
355
356
  buffer.writeVarint32(enc.remaining());
356
357
  buffer.append(enc);
357
358
  return isNew ? buffer.flip() : buffer;
@@ -560,6 +561,7 @@ MessagePrototype.encodeJSON = function() {
560
561
  * @name ProtoBuf.Builder.Message.decode
561
562
  * @function
562
563
  * @param {!ByteBuffer|!ArrayBuffer|!Buffer|string} buffer Buffer to decode from
564
+ * @param {(number|string)=} length Message length. Defaults to decode all the remainig data.
563
565
  * @param {string=} enc Encoding if buffer is a string: hex, utf8 (not recommended), defaults to base64
564
566
  * @return {!ProtoBuf.Builder.Message} Decoded message
565
567
  * @throws {Error} If the message cannot be decoded or if required fields are missing. The later still
@@ -568,7 +570,10 @@ MessagePrototype.encodeJSON = function() {
568
570
  * @see ProtoBuf.Builder.Message.decode64
569
571
  * @see ProtoBuf.Builder.Message.decodeHex
570
572
  */
571
- Message.decode = function(buffer, enc) {
573
+ Message.decode = function(buffer, length, enc) {
574
+ if (typeof length === 'string')
575
+ enc = length,
576
+ length = -1;
572
577
  if (typeof buffer === 'string')
573
578
  buffer = ByteBuffer.wrap(buffer, enc ? enc : "base64");
574
579
  buffer = ByteBuffer.isByteBuffer(buffer) ? buffer : ByteBuffer.wrap(buffer); // May throw
@@ -77,6 +77,9 @@ for (var i=0; i<rpc.length; i++) {
77
77
  callback(err);
78
78
  return;
79
79
  }
80
+ // Coalesce to empty string when service response has empty content
81
+ if (res === null)
82
+ res = ''
80
83
  try { res = method.resolvedResponseType.clazz.decode(res); } catch (notABuffer) {}
81
84
  if (!res || !(res instanceof method.resolvedResponseType.clazz)) {
82
85
  callback(Error("Illegal response type received in service method "+ T.name+"#"+method.name));
@@ -243,13 +243,12 @@ ProtoBuf.Builder = (function(ProtoBuf, Lang, Reflect) {
243
243
  subObj.push(svc);
244
244
  });
245
245
 
246
- // Set extension range
246
+ // Set extension ranges
247
247
  if (def["extensions"]) {
248
- obj.extensions = def["extensions"];
249
- if (obj.extensions[0] < ProtoBuf.ID_MIN)
250
- obj.extensions[0] = ProtoBuf.ID_MIN;
251
- if (obj.extensions[1] > ProtoBuf.ID_MAX)
252
- obj.extensions[1] = ProtoBuf.ID_MAX;
248
+ if (typeof def["extensions"][0] === 'number') // pre 5.0.1
249
+ obj.extensions = [ def["extensions"] ];
250
+ else
251
+ obj.extensions = def["extensions"];
253
252
  }
254
253
 
255
254
  // Create on top of current namespace
@@ -288,8 +287,16 @@ ProtoBuf.Builder = (function(ProtoBuf, Lang, Reflect) {
288
287
  def["fields"].forEach(function(fld) {
289
288
  if (obj.getChild(fld['id']|0) !== null)
290
289
  throw Error("duplicate extended field id in "+obj.name+": "+fld['id']);
291
- if (fld['id'] < obj.extensions[0] || fld['id'] > obj.extensions[1])
292
- throw Error("illegal extended field id in "+obj.name+": "+fld['id']+" ("+obj.extensions.join(' to ')+" expected)");
290
+ // Check if field id is allowed to be extended
291
+ if (obj.extensions) {
292
+ var valid = false;
293
+ obj.extensions.forEach(function(range) {
294
+ if (fld["id"] >= range[0] && fld["id"] <= range[1])
295
+ valid = true;
296
+ });
297
+ if (!valid)
298
+ throw Error("illegal extended field id in "+obj.name+": "+fld['id']+" (not within valid ranges)");
299
+ }
293
300
  // Convert extension field names to camel case notation if the override is set
294
301
  var name = fld["name"];
295
302
  if (this.options['convertFieldsToCamelCase'])
@@ -50,7 +50,8 @@ ParserPrototype.parse = function() {
50
50
  // "syntax": undefined
51
51
  };
52
52
  var token,
53
- head = true;
53
+ head = true,
54
+ weak;
54
55
  try {
55
56
  while (token = this.tn.next()) {
56
57
  switch (token) {
@@ -67,11 +68,12 @@ ParserPrototype.parse = function() {
67
68
  if (!head)
68
69
  throw Error("unexpected 'import'");
69
70
  token = this.tn.peek();
70
- if (token === "public") // ignored
71
+ if (token === "public" || (weak = token === "weak")) // token ignored
71
72
  this.tn.next();
72
73
  token = this._readString();
73
74
  this.tn.skip(";");
74
- topLevel["imports"].push(token);
75
+ if (!weak) // import ignored
76
+ topLevel["imports"].push(token);
75
77
  break;
76
78
  case 'syntax':
77
79
  if (!head)
@@ -426,11 +428,11 @@ ParserPrototype._parseMessage = function(parent, fld) {
426
428
  else if (token === "service")
427
429
  this._parseService(msg);
428
430
  else if (token === "extensions")
429
- this._parseExtensions(msg);
431
+ msg["extensions"] = this._parseExtensionRanges();
432
+ else if (token === "reserved")
433
+ this._parseIgnored(); // TODO
430
434
  else if (token === "extend")
431
435
  this._parseExtend(msg);
432
- else if (token === "reserved")
433
- this._parseMessageReserved(msg);
434
436
  else if (Lang.TYPEREF.test(token)) {
435
437
  if (!this.proto3)
436
438
  throw Error("illegal field rule: "+token);
@@ -444,17 +446,10 @@ ParserPrototype._parseMessage = function(parent, fld) {
444
446
  };
445
447
 
446
448
  /**
447
- * Parses a message's reserved ids / names statement.
448
- * @param {!Object} msg Message definition
449
+ * Parses an ignored statement.
449
450
  * @private
450
451
  */
451
- ParserPrototype._parseMessageReserved = function(msg) {
452
- // TODO: This currently just skips a reserved statement for compatibility.
453
- // Valid formats are
454
- // reserved 2, 15, 9 to 11;
455
- // for reserved ids or
456
- // reserved "foo", "bar";
457
- // for reserved names.
452
+ ParserPrototype._parseIgnored = function() {
458
453
  while (this.tn.peek() !== ';')
459
454
  this.tn.next();
460
455
  this.tn.skip(";");
@@ -622,29 +617,43 @@ ParserPrototype._parseEnum = function(msg) {
622
617
  };
623
618
 
624
619
  /**
625
- * Parses an extensions statement.
626
- * @param {!Object} msg Message object
620
+ * Parses extension / reserved ranges.
621
+ * @returns {!Array.<!Array.<number>>}
627
622
  * @private
628
623
  */
629
- ParserPrototype._parseExtensions = function(msg) {
630
- var token = this.tn.next(),
624
+ ParserPrototype._parseExtensionRanges = function() {
625
+ var ranges = [];
626
+ var token,
627
+ range,
628
+ value;
629
+ do {
631
630
  range = [];
632
- if (token === "min")
633
- range.push(ProtoBuf.ID_MIN);
634
- else if (token === "max")
635
- range.push(ProtoBuf.ID_MAX);
636
- else
637
- range.push(mkNumber(token));
638
- this.tn.skip("to");
639
- token = this.tn.next();
640
- if (token === "min")
641
- range.push(ProtoBuf.ID_MIN);
642
- else if (token === "max")
643
- range.push(ProtoBuf.ID_MAX);
644
- else
645
- range.push(mkNumber(token));
631
+ while (true) {
632
+ token = this.tn.next();
633
+ switch (token) {
634
+ case "min":
635
+ value = ProtoBuf.ID_MIN;
636
+ break;
637
+ case "max":
638
+ value = ProtoBuf.ID_MAX;
639
+ break;
640
+ default:
641
+ value = mkNumber(token);
642
+ break;
643
+ }
644
+ range.push(value);
645
+ if (range.length === 2)
646
+ break;
647
+ if (this.tn.peek() !== "to") {
648
+ range.push(value);
649
+ break;
650
+ }
651
+ this.tn.next();
652
+ }
653
+ ranges.push(range);
654
+ } while (this.tn.omit(","));
646
655
  this.tn.skip(";");
647
- msg["extensions"] = range;
656
+ return ranges;
648
657
  };
649
658
 
650
659
  /**
@@ -102,9 +102,10 @@ function mkLong(value, unsigned) {
102
102
  * @expose
103
103
  */
104
104
  ElementPrototype.verifyValue = function(value) {
105
- var fail = function(val, msg) {
106
- throw Error("Illegal value for "+this.toString(true)+" of type "+this.type.name+": "+val+" ("+msg+")");
107
- }.bind(this);
105
+ var self = this;
106
+ function fail(val, msg) {
107
+ throw Error("Illegal value for "+self.toString(true)+" of type "+self.type.name+": "+val+" ("+msg+")");
108
+ }
108
109
  switch (this.type) {
109
110
  // Signed 32bit
110
111
  case ProtoBuf.TYPES["int32"]:
@@ -165,9 +165,10 @@ FieldPrototype.build = function() {
165
165
  */
166
166
  FieldPrototype.verifyValue = function(value, skipRepeated) {
167
167
  skipRepeated = skipRepeated || false;
168
- var fail = function(val, msg) {
169
- throw Error("Illegal value for "+this.toString(true)+" of type "+this.type.name+": "+val+" ("+msg+")");
170
- }.bind(this);
168
+ var self = this;
169
+ function fail(val, msg) {
170
+ throw Error("Illegal value for "+self.toString(true)+" of type "+self.type.name+": "+val+" ("+msg+")");
171
+ }
171
172
  if (value === null) { // NULL values for optional fields
172
173
  if (this.required)
173
174
  fail(typeof value, "required");
@@ -20,10 +20,10 @@ var Message = function(builder, parent, name, options, isGroup, syntax) {
20
20
 
21
21
  /**
22
22
  * Extensions range.
23
- * @type {!Array.<number>}
23
+ * @type {!Array.<number>|undefined}
24
24
  * @expose
25
25
  */
26
- this.extensions = [ProtoBuf.ID_MIN, ProtoBuf.ID_MAX];
26
+ this.extensions = undefined;
27
27
 
28
28
  /**
29
29
  * Runtime message class.
@@ -204,7 +204,7 @@ function skipTillGroupEnd(expectedId, buf) {
204
204
  /**
205
205
  * Decodes an encoded message and returns the decoded message.
206
206
  * @param {ByteBuffer} buffer ByteBuffer to decode from
207
- * @param {number=} length Message length. Defaults to decode all the available data.
207
+ * @param {number=} length Message length. Defaults to decode all remaining data.
208
208
  * @param {number=} expectedGroupEndId Expected GROUPEND id if this is a legacy group
209
209
  * @return {ProtoBuf.Builder.Message} Decoded message
210
210
  * @throws {Error} If the message cannot be decoded