protobufjs 8.1.6-experimental → 8.2.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 (76) hide show
  1. package/README.md +225 -570
  2. package/dist/light/protobuf.js +2041 -1482
  3. package/dist/light/protobuf.js.map +1 -1
  4. package/dist/light/protobuf.min.js +3 -3
  5. package/dist/light/protobuf.min.js.map +1 -1
  6. package/dist/minimal/protobuf.js +1167 -863
  7. package/dist/minimal/protobuf.js.map +1 -1
  8. package/dist/minimal/protobuf.min.js +3 -3
  9. package/dist/minimal/protobuf.min.js.map +1 -1
  10. package/dist/protobuf.js +2173 -1527
  11. package/dist/protobuf.js.map +1 -1
  12. package/dist/protobuf.min.js +3 -3
  13. package/dist/protobuf.min.js.map +1 -1
  14. package/ext/README.md +81 -0
  15. package/ext/descriptor/README.md +3 -70
  16. package/ext/descriptor/index.d.ts +1 -190
  17. package/ext/descriptor/index.js +1 -1161
  18. package/ext/descriptor.d.ts +309 -0
  19. package/ext/descriptor.js +1241 -0
  20. package/ext/textformat.d.ts +24 -0
  21. package/ext/textformat.js +1227 -0
  22. package/google/protobuf/compiler/plugin.json +126 -0
  23. package/google/protobuf/compiler/plugin.proto +47 -0
  24. package/google/protobuf/descriptor.json +2 -2
  25. package/google/protobuf/descriptor.proto +2 -1
  26. package/index.d.ts +585 -476
  27. package/package.json +22 -40
  28. package/src/converter.js +63 -27
  29. package/src/decoder.js +126 -49
  30. package/src/encoder.js +10 -2
  31. package/src/enum.js +4 -1
  32. package/src/field.js +10 -7
  33. package/src/mapfield.js +1 -0
  34. package/src/message.js +7 -6
  35. package/src/method.js +4 -3
  36. package/src/namespace.js +31 -12
  37. package/src/object.js +24 -19
  38. package/src/oneof.js +2 -0
  39. package/src/parse.js +128 -46
  40. package/src/reader.js +145 -30
  41. package/src/reader_buffer.js +24 -3
  42. package/src/root.js +10 -4
  43. package/src/service.js +15 -6
  44. package/src/tokenize.js +6 -1
  45. package/src/type.js +57 -27
  46. package/src/types.js +1 -1
  47. package/src/util/aspromise.d.ts +13 -0
  48. package/src/util/aspromise.js +52 -0
  49. package/src/util/base64.d.ts +32 -0
  50. package/src/util/base64.js +146 -0
  51. package/src/util/codegen.d.ts +31 -0
  52. package/src/util/codegen.js +113 -0
  53. package/src/util/eventemitter.d.ts +45 -0
  54. package/src/util/eventemitter.js +84 -0
  55. package/src/util/fetch.d.ts +56 -0
  56. package/src/util/fetch.js +112 -0
  57. package/src/util/float.d.ts +83 -0
  58. package/src/util/float.js +335 -0
  59. package/src/util/fs.js +11 -0
  60. package/src/util/inquire.d.ts +10 -0
  61. package/src/util/inquire.js +38 -0
  62. package/src/util/minimal.js +74 -12
  63. package/src/util/path.d.ts +22 -0
  64. package/src/util/path.js +72 -0
  65. package/src/util/patterns.js +8 -0
  66. package/src/util/pool.d.ts +32 -0
  67. package/src/util/pool.js +48 -0
  68. package/src/util/utf8.d.ts +24 -0
  69. package/src/util/utf8.js +130 -0
  70. package/src/util.js +18 -13
  71. package/src/verifier.js +7 -4
  72. package/src/wrappers.js +4 -3
  73. package/src/writer.js +33 -5
  74. package/src/writer_buffer.js +18 -1
  75. package/tsconfig.json +2 -2
  76. package/ext/descriptor/test.js +0 -54
package/src/parse.js CHANGED
@@ -23,9 +23,9 @@ var base10Re = /^[1-9][0-9]*$/,
23
23
  base16NegRe = /^-?0[x][0-9a-fA-F]+$/,
24
24
  base8Re = /^0[0-7]+$/,
25
25
  base8NegRe = /^-?0[0-7]+$/,
26
- numberRe = /^(?![eE])[0-9]*(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?$/,
26
+ numberRe = util.patterns.numberRe,
27
27
  nameRe = /^[a-zA-Z_][a-zA-Z_0-9]*$/,
28
- typeRefRe = /^(?:\.?[a-zA-Z_][a-zA-Z_0-9]*)(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*$/;
28
+ typeRefRe = util.patterns.typeRefRe;
29
29
 
30
30
  /**
31
31
  * Result object returned from {@link parse}.
@@ -261,6 +261,16 @@ function parse(source, root, options) {
261
261
  var token = peek();
262
262
  var whichImports;
263
263
  switch (token) {
264
+ case "option":
265
+ if (edition < "2024") {
266
+ throw illegal("option");
267
+ }
268
+ // Import options are only used for resolving options, which we don't
269
+ // do. We can just throw them out.
270
+ next();
271
+ readString();
272
+ skip(";");
273
+ return;
264
274
  case "weak":
265
275
  whichImports = weakImports || (weakImports = []);
266
276
  next();
@@ -291,7 +301,7 @@ function parse(source, root, options) {
291
301
  function parseEdition() {
292
302
  skip("=");
293
303
  edition = readString();
294
- const supportedEditions = ["2023"];
304
+ const supportedEditions = ["2023", "2024"];
295
305
 
296
306
  /* istanbul ignore if */
297
307
  if (!supportedEditions.includes(edition))
@@ -301,7 +311,10 @@ function parse(source, root, options) {
301
311
  }
302
312
 
303
313
 
304
- function parseCommon(parent, token) {
314
+ function parseCommon(parent, token, depth) {
315
+ if (depth === undefined)
316
+ depth = 0;
317
+ // depth is checked by dispatched functions
305
318
  switch (token) {
306
319
 
307
320
  case "option":
@@ -310,19 +323,35 @@ function parse(source, root, options) {
310
323
  return true;
311
324
 
312
325
  case "message":
313
- parseType(parent, token);
326
+ parseType(parent, token, depth + 1);
314
327
  return true;
315
328
 
316
329
  case "enum":
317
330
  parseEnum(parent, token);
318
331
  return true;
319
332
 
333
+ case "export":
334
+ case "local":
335
+ if (edition < "2024") {
336
+ return false;
337
+ }
338
+ token = next();
339
+ if (token === "export" || token === "local") {
340
+ return false;
341
+ }
342
+ if (token !== "message" && token !== "enum") {
343
+ return false;
344
+ }
345
+ /* eslint-disable no-warning-comments */
346
+ // TODO: actually enforce visiblity modifiers like protoc does.
347
+ return parseCommon(parent, token, depth);
348
+
320
349
  case "service":
321
- parseService(parent, token);
350
+ parseService(parent, token, depth + 1);
322
351
  return true;
323
352
 
324
353
  case "extend":
325
- parseExtension(parent, token);
354
+ parseExtension(parent, token, depth);
326
355
  return true;
327
356
  }
328
357
  return false;
@@ -350,7 +379,11 @@ function parse(source, root, options) {
350
379
  }
351
380
  }
352
381
 
353
- function parseType(parent, token) {
382
+ function parseType(parent, token, depth) {
383
+ if (depth === undefined)
384
+ depth = 0;
385
+ if (depth > util.nestingLimit)
386
+ throw Error("max depth exceeded");
354
387
 
355
388
  /* istanbul ignore if */
356
389
  if (!nameRe.test(token = next()))
@@ -358,11 +391,14 @@ function parse(source, root, options) {
358
391
 
359
392
  var type = new Type(token);
360
393
  ifBlock(type, function parseType_block(token) {
361
- if (parseCommon(type, token))
394
+ if (parseCommon(type, token, depth))
362
395
  return;
363
396
 
364
397
  switch (token) {
365
398
 
399
+ case ";":
400
+ break;
401
+
366
402
  case "map":
367
403
  parseMapField(type, token);
368
404
  break;
@@ -372,22 +408,22 @@ function parse(source, root, options) {
372
408
  throw illegal(token);
373
409
  /* eslint-disable no-fallthrough */
374
410
  case "repeated":
375
- parseField(type, token);
411
+ parseField(type, token, undefined, depth + 1);
376
412
  break;
377
413
 
378
414
  case "optional":
379
415
  /* istanbul ignore if */
380
416
  if (edition === "proto3") {
381
- parseField(type, "proto3_optional");
417
+ parseField(type, "proto3_optional", undefined, depth + 1);
382
418
  } else if (edition !== "proto2") {
383
419
  throw illegal(token);
384
420
  } else {
385
- parseField(type, "optional");
421
+ parseField(type, "optional", undefined, depth + 1);
386
422
  }
387
423
  break;
388
424
 
389
425
  case "oneof":
390
- parseOneOf(type, token);
426
+ parseOneOf(type, token, depth + 1);
391
427
  break;
392
428
 
393
429
  case "extensions":
@@ -405,7 +441,7 @@ function parse(source, root, options) {
405
441
  }
406
442
 
407
443
  push(token);
408
- parseField(type, "optional");
444
+ parseField(type, "optional", undefined, depth + 1);
409
445
  break;
410
446
  }
411
447
  });
@@ -415,10 +451,10 @@ function parse(source, root, options) {
415
451
  }
416
452
  }
417
453
 
418
- function parseField(parent, rule, extend) {
454
+ function parseField(parent, rule, extend, depth) {
419
455
  var type = next();
420
456
  if (type === "group") {
421
- parseGroup(parent, rule);
457
+ parseGroup(parent, rule, extend, depth);
422
458
  return;
423
459
  }
424
460
  // Type names can consume multiple tokens, in multiple variants:
@@ -475,7 +511,11 @@ function parse(source, root, options) {
475
511
  }
476
512
  }
477
513
 
478
- function parseGroup(parent, rule) {
514
+ function parseGroup(parent, rule, extend, depth) {
515
+ if (depth === undefined)
516
+ depth = 0;
517
+ if (depth > util.nestingLimit)
518
+ throw Error("max depth exceeded");
479
519
  if (edition >= 2023) {
480
520
  throw illegal("group");
481
521
  }
@@ -492,31 +532,34 @@ function parse(source, root, options) {
492
532
  var id = parseId(next());
493
533
  var type = new Type(name);
494
534
  type.group = true;
495
- var field = new Field(fieldName, id, name, rule);
535
+ var field = new Field(fieldName, id, name, rule, extend);
496
536
  field.filename = parse.filename;
497
537
  ifBlock(type, function parseGroup_block(token) {
498
538
  switch (token) {
499
539
 
540
+ case ";":
541
+ break;
542
+
500
543
  case "option":
501
544
  parseOption(type, token);
502
545
  skip(";");
503
546
  break;
504
547
  case "required":
505
548
  case "repeated":
506
- parseField(type, token);
549
+ parseField(type, token, undefined, depth + 1);
507
550
  break;
508
551
 
509
552
  case "optional":
510
553
  /* istanbul ignore if */
511
554
  if (edition === "proto3") {
512
- parseField(type, "proto3_optional");
555
+ parseField(type, "proto3_optional", undefined, depth + 1);
513
556
  } else {
514
- parseField(type, "optional");
557
+ parseField(type, "optional", undefined, depth + 1);
515
558
  }
516
559
  break;
517
560
 
518
561
  case "message":
519
- parseType(type, token);
562
+ parseType(type, token, depth + 1);
520
563
  break;
521
564
 
522
565
  case "enum":
@@ -527,6 +570,24 @@ function parse(source, root, options) {
527
570
  readRanges(type.reserved || (type.reserved = []), true);
528
571
  break;
529
572
 
573
+ case "export":
574
+ case "local":
575
+ if (edition < "2024") {
576
+ throw illegal(token);
577
+ }
578
+ token = next();
579
+ switch (token) {
580
+ case "message":
581
+ parseType(type, token, depth + 1);
582
+ break;
583
+ case "enum":
584
+ parseType(type, token, depth + 1);
585
+ break;
586
+ default:
587
+ throw illegal(token);
588
+ }
589
+ break;
590
+
530
591
  /* istanbul ignore next */
531
592
  default:
532
593
  throw illegal(token); // there are no groups with proto3 semantics
@@ -534,6 +595,10 @@ function parse(source, root, options) {
534
595
  });
535
596
  parent.add(type)
536
597
  .add(field);
598
+ if (parent === ptr) {
599
+ topLevelObjects.push(type);
600
+ topLevelObjects.push(field);
601
+ }
537
602
  }
538
603
 
539
604
  function parseMapField(parent) {
@@ -575,7 +640,7 @@ function parse(source, root, options) {
575
640
  parent.add(field);
576
641
  }
577
642
 
578
- function parseOneOf(parent, token) {
643
+ function parseOneOf(parent, token, depth) {
579
644
 
580
645
  /* istanbul ignore if */
581
646
  if (!nameRe.test(token = next()))
@@ -588,7 +653,7 @@ function parse(source, root, options) {
588
653
  skip(";");
589
654
  } else {
590
655
  push(token);
591
- parseField(oneof, "optional");
656
+ parseField(oneof, "optional", undefined, depth);
592
657
  }
593
658
  });
594
659
  parent.add(oneof);
@@ -603,6 +668,9 @@ function parse(source, root, options) {
603
668
  var enm = new Enum(token);
604
669
  ifBlock(enm, function parseEnum_block(token) {
605
670
  switch(token) {
671
+ case ";":
672
+ break;
673
+
606
674
  case "option":
607
675
  parseOption(enm, token);
608
676
  skip(";");
@@ -693,7 +761,11 @@ function parse(source, root, options) {
693
761
  setParsedOption(parent, option, optionValue, propName);
694
762
  }
695
763
 
696
- function parseOptionValue(parent, name) {
764
+ function parseOptionValue(parent, name, depth) {
765
+ if (depth === undefined)
766
+ depth = 0;
767
+ if (depth > util.recursionLimit)
768
+ throw Error("max depth exceeded");
697
769
  // { a: "foo" b { c: "bar" } }
698
770
  if (skip("{", true)) {
699
771
  var objectResult = {};
@@ -716,18 +788,20 @@ function parse(source, root, options) {
716
788
  // option (my_option) = {
717
789
  // repeated_value: [ "foo", "bar" ]
718
790
  // };
719
- value = parseOptionValue(parent, name + "." + token);
791
+ value = parseOptionValue(parent, name + "." + token, depth + 1);
720
792
  } else if (peek() === "[") {
721
793
  value = [];
722
794
  var lastValue;
723
795
  if (skip("[", true)) {
724
- do {
725
- lastValue = readValue(true);
726
- value.push(lastValue);
727
- } while (skip(",", true));
728
- skip("]");
729
- if (typeof lastValue !== "undefined") {
730
- setOption(parent, name + "." + token, lastValue);
796
+ if (!skip("]", true)) {
797
+ do {
798
+ lastValue = readValue(true);
799
+ value.push(lastValue);
800
+ } while (skip(",", true));
801
+ skip("]");
802
+ if (typeof lastValue !== "undefined") {
803
+ setOption(parent, name + "." + token, lastValue);
804
+ }
731
805
  }
732
806
  }
733
807
  } else {
@@ -740,7 +814,8 @@ function parse(source, root, options) {
740
814
  if (prevValue)
741
815
  value = [].concat(prevValue).concat(value);
742
816
 
743
- objectResult[propName] = value;
817
+ if (propName !== "__proto__")
818
+ objectResult[propName] = value;
744
819
 
745
820
  // Semicolons and commas can be optional
746
821
  skip(",", true);
@@ -780,7 +855,11 @@ function parse(source, root, options) {
780
855
  return parent;
781
856
  }
782
857
 
783
- function parseService(parent, token) {
858
+ function parseService(parent, token, depth) {
859
+ if (depth === undefined)
860
+ depth = 0;
861
+ if (depth > util.recursionLimit)
862
+ throw Error("max depth exceeded");
784
863
 
785
864
  /* istanbul ignore if */
786
865
  if (!nameRe.test(token = next()))
@@ -788,11 +867,13 @@ function parse(source, root, options) {
788
867
 
789
868
  var service = new Service(token);
790
869
  ifBlock(service, function parseService_block(token) {
791
- if (parseCommon(service, token)) {
870
+ if (parseCommon(service, token, depth)) {
792
871
  return;
793
872
  }
794
873
 
795
874
  /* istanbul ignore else */
875
+ if (token === ";")
876
+ return;
796
877
  if (token === "rpc")
797
878
  parseMethod(service, token);
798
879
  else
@@ -844,6 +925,8 @@ function parse(source, root, options) {
844
925
  ifBlock(method, function parseMethod_block(token) {
845
926
 
846
927
  /* istanbul ignore else */
928
+ if (token === ";")
929
+ return;
847
930
  if (token === "option") {
848
931
  parseOption(method, token);
849
932
  skip(";");
@@ -854,7 +937,7 @@ function parse(source, root, options) {
854
937
  parent.add(method);
855
938
  }
856
939
 
857
- function parseExtension(parent, token) {
940
+ function parseExtension(parent, token, depth) {
858
941
 
859
942
  /* istanbul ignore if */
860
943
  if (!typeRefRe.test(token = next()))
@@ -866,15 +949,15 @@ function parse(source, root, options) {
866
949
 
867
950
  case "required":
868
951
  case "repeated":
869
- parseField(parent, token, reference);
952
+ parseField(parent, token, reference, depth + 1);
870
953
  break;
871
954
 
872
955
  case "optional":
873
956
  /* istanbul ignore if */
874
957
  if (edition === "proto3") {
875
- parseField(parent, "proto3_optional", reference);
958
+ parseField(parent, "proto3_optional", reference, depth + 1);
876
959
  } else {
877
- parseField(parent, "optional", reference);
960
+ parseField(parent, "optional", reference, depth + 1);
878
961
  }
879
962
  break;
880
963
 
@@ -883,7 +966,7 @@ function parse(source, root, options) {
883
966
  if (edition === "proto2" || !typeRefRe.test(token))
884
967
  throw illegal(token);
885
968
  push(token);
886
- parseField(parent, "optional", reference);
969
+ parseField(parent, "optional", reference, depth + 1);
887
970
  break;
888
971
  }
889
972
  });
@@ -893,6 +976,9 @@ function parse(source, root, options) {
893
976
  while ((token = next()) !== null) {
894
977
  switch (token) {
895
978
 
979
+ case ";":
980
+ break;
981
+
896
982
  case "package":
897
983
 
898
984
  /* istanbul ignore if */
@@ -904,10 +990,6 @@ function parse(source, root, options) {
904
990
 
905
991
  case "import":
906
992
 
907
- /* istanbul ignore if */
908
- if (!head)
909
- throw illegal(token);
910
-
911
993
  parseImport();
912
994
  break;
913
995
 
@@ -935,7 +1017,7 @@ function parse(source, root, options) {
935
1017
  default:
936
1018
 
937
1019
  /* istanbul ignore else */
938
- if (parseCommon(ptr, token)) {
1020
+ if (parseCommon(ptr, token, 0)) {
939
1021
  head = false;
940
1022
  continue;
941
1023
  }
package/src/reader.js CHANGED
@@ -78,28 +78,108 @@ Reader.create = create();
78
78
 
79
79
  Reader.prototype._slice = util.Array.prototype.subarray || /* istanbul ignore next */ util.Array.prototype.slice;
80
80
 
81
+ /**
82
+ * Returns raw bytes from the backing buffer without advancing the reader.
83
+ * @param {number} start Start offset
84
+ * @param {number} end End offset
85
+ * @returns {Uint8Array} Raw bytes
86
+ */
87
+ Reader.prototype.raw = function read_raw(start, end) {
88
+ if (Array.isArray(this.buf)) // plain array
89
+ return this.buf.slice(start, end);
90
+
91
+ if (start === end) // fix for IE 10/Win8 and others' subarray returning array of size 1
92
+ return new this.buf.constructor(0);
93
+ return this._slice.call(this.buf, start, end);
94
+ };
95
+
81
96
  /**
82
97
  * Reads a varint as an unsigned 32 bit value.
83
98
  * @function
84
99
  * @returns {number} Value read
85
100
  */
86
- Reader.prototype.uint32 = (function read_uint32_setup() {
87
- var value = 4294967295; // optimizer type-hint, tends to deopt otherwise (?!)
88
- return function read_uint32() {
89
- value = ( this.buf[this.pos] & 127 ) >>> 0; if (this.buf[this.pos++] < 128) return value;
90
- value = (value | (this.buf[this.pos] & 127) << 7) >>> 0; if (this.buf[this.pos++] < 128) return value;
91
- value = (value | (this.buf[this.pos] & 127) << 14) >>> 0; if (this.buf[this.pos++] < 128) return value;
92
- value = (value | (this.buf[this.pos] & 127) << 21) >>> 0; if (this.buf[this.pos++] < 128) return value;
93
- value = (value | (this.buf[this.pos] & 15) << 28) >>> 0; if (this.buf[this.pos++] < 128) return value;
101
+ Reader.prototype.uint32 = function read_uint32() {
102
+ var buf = this.buf,
103
+ pos = this.pos,
104
+ value = (buf[pos] & 127) >>> 0;
105
+ if (buf[pos++] < 128) {
106
+ this.pos = pos;
107
+ return value;
108
+ }
109
+ value = (value | (buf[pos] & 127) << 7) >>> 0;
110
+ if (buf[pos++] < 128) {
111
+ this.pos = pos;
112
+ return value;
113
+ }
114
+ value = (value | (buf[pos] & 127) << 14) >>> 0;
115
+ if (buf[pos++] < 128) {
116
+ this.pos = pos;
117
+ return value;
118
+ }
119
+ value = (value | (buf[pos] & 127) << 21) >>> 0;
120
+ if (buf[pos++] < 128) {
121
+ this.pos = pos;
122
+ return value;
123
+ }
124
+ value = (value | (buf[pos] & 15) << 28) >>> 0;
125
+ if (buf[pos++] < 128) {
126
+ this.pos = pos;
127
+ return value;
128
+ }
94
129
 
130
+ for (var i = 0; i < 5; ++i) {
95
131
  /* istanbul ignore if */
96
- if ((this.pos += 5) > this.len) {
97
- this.pos = this.len;
98
- throw indexOutOfRange(this, 10);
132
+ if (pos >= this.len) {
133
+ this.pos = pos;
134
+ throw indexOutOfRange(this);
135
+ }
136
+ if (buf[pos++] < 128) {
137
+ this.pos = pos;
138
+ return value;
99
139
  }
140
+ }
141
+ /* istanbul ignore next */
142
+ this.pos = pos;
143
+ throw Error("invalid varint encoding");
144
+ };
145
+
146
+ /**
147
+ * Reads a field tag.
148
+ * @function
149
+ * @returns {number} Tag read
150
+ */
151
+ Reader.prototype.tag = function read_tag() {
152
+ var buf = this.buf,
153
+ pos = this.pos,
154
+ value = (buf[pos] & 127) >>> 0;
155
+ if (buf[pos++] < 128) {
156
+ this.pos = pos;
100
157
  return value;
101
- };
102
- })();
158
+ }
159
+ value = (value | (buf[pos] & 127) << 7) >>> 0;
160
+ if (buf[pos++] < 128) {
161
+ this.pos = pos;
162
+ return value;
163
+ }
164
+ value = (value | (buf[pos] & 127) << 14) >>> 0;
165
+ if (buf[pos++] < 128) {
166
+ this.pos = pos;
167
+ return value;
168
+ }
169
+ value = (value | (buf[pos] & 127) << 21) >>> 0;
170
+ if (buf[pos++] < 128) {
171
+ this.pos = pos;
172
+ return value;
173
+ }
174
+ value = (value | (buf[pos] & 15) << 28) >>> 0;
175
+ if (buf[pos] < 128 && (buf[pos] & 112) === 0) {
176
+ this.pos = pos + 1;
177
+ return value;
178
+ }
179
+
180
+ this.pos = pos + 1;
181
+ throw Error("invalid tag encoding");
182
+ };
103
183
 
104
184
  /**
105
185
  * Reads a varint as a signed 32 bit value.
@@ -201,7 +281,20 @@ function readLongVarint() {
201
281
  * @returns {boolean} Value read
202
282
  */
203
283
  Reader.prototype.bool = function read_bool() {
204
- return this.uint32() !== 0;
284
+ var value = false,
285
+ b;
286
+ for (var i = 0; i < 10; ++i) {
287
+ /* istanbul ignore if */
288
+ if (this.pos >= this.len)
289
+ throw indexOutOfRange(this);
290
+ b = this.buf[this.pos++];
291
+ if (b & 127)
292
+ value = true;
293
+ if (b < 128)
294
+ return value;
295
+ }
296
+ /* istanbul ignore next */
297
+ throw Error("invalid varint encoding");
205
298
  };
206
299
 
207
300
  function readFixed32_end(buf, end) { // note that this uses `end`, not `pos`
@@ -309,17 +402,8 @@ Reader.prototype.bytes = function read_bytes() {
309
402
  if (end > this.len)
310
403
  throw indexOutOfRange(this, length);
311
404
 
312
- this.pos += length;
313
- if (Array.isArray(this.buf)) // plain array
314
- return this.buf.slice(start, end);
315
-
316
- if (start === end) { // fix for IE 10/Win8 and others' subarray returning array of size 1
317
- var nativeBuffer = util.Buffer;
318
- return nativeBuffer
319
- ? nativeBuffer.alloc(0)
320
- : new this.buf.constructor(0);
321
- }
322
- return this._slice.call(this.buf, start, end);
405
+ this.pos = end;
406
+ return this.raw(start, end);
323
407
  };
324
408
 
325
409
  /**
@@ -327,8 +411,16 @@ Reader.prototype.bytes = function read_bytes() {
327
411
  * @returns {string} Value read
328
412
  */
329
413
  Reader.prototype.string = function read_string() {
330
- var bytes = this.bytes();
331
- return utf8.read(bytes, 0, bytes.length);
414
+ var length = this.uint32(),
415
+ start = this.pos,
416
+ end = this.pos + length;
417
+
418
+ /* istanbul ignore if */
419
+ if (end > this.len)
420
+ throw indexOutOfRange(this, length);
421
+
422
+ this.pos = end;
423
+ return utf8.read(this.buf, start, end);
332
424
  };
333
425
 
334
426
  /**
@@ -352,12 +444,25 @@ Reader.prototype.skip = function skip(length) {
352
444
  return this;
353
445
  };
354
446
 
447
+ /**
448
+ * Recursion limit.
449
+ * @type {number}
450
+ */
451
+ Reader.recursionLimit = util.recursionLimit;
452
+
355
453
  /**
356
454
  * Skips the next element of the specified wire type.
357
455
  * @param {number} wireType Wire type received
456
+ * @param {number} [depth] Depth of recursion to control nested calls; 0 if omitted
457
+ * @param {number} [fieldNumber] Field number for validating group end tags
358
458
  * @returns {Reader} `this`
359
459
  */
360
- Reader.prototype.skipType = function(wireType) {
460
+ Reader.prototype.skipType = function(wireType, depth, fieldNumber) {
461
+ if (depth === undefined) depth = 0;
462
+ if (depth > Reader.recursionLimit)
463
+ throw Error("max depth exceeded");
464
+ if (fieldNumber === 0)
465
+ throw Error("illegal tag: field number 0");
361
466
  switch (wireType) {
362
467
  case 0:
363
468
  this.skip();
@@ -369,8 +474,18 @@ Reader.prototype.skipType = function(wireType) {
369
474
  this.skip(this.uint32());
370
475
  break;
371
476
  case 3:
372
- while ((wireType = this.uint32() & 7) !== 4) {
373
- this.skipType(wireType);
477
+ while (true) {
478
+ var tag = this.tag();
479
+ var nestedField = tag >>> 3;
480
+ wireType = tag & 7;
481
+ if (!nestedField)
482
+ throw Error("illegal tag: field number 0");
483
+ if (wireType === 4) {
484
+ if (fieldNumber !== undefined && nestedField !== fieldNumber)
485
+ throw Error("invalid end group tag");
486
+ break;
487
+ }
488
+ this.skipType(wireType, depth + 1, nestedField);
374
489
  }
375
490
  break;
376
491
  case 5: