buffer.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. 'use strict';
  2. const inherits = require('inherits');
  3. const Reporter = require('../base/reporter').Reporter;
  4. const Buffer = require('safer-buffer').Buffer;
  5. function DecoderBuffer(base, options) {
  6. Reporter.call(this, options);
  7. if (!Buffer.isBuffer(base)) {
  8. this.error('Input not Buffer');
  9. return;
  10. }
  11. this.base = base;
  12. this.offset = 0;
  13. this.length = base.length;
  14. }
  15. inherits(DecoderBuffer, Reporter);
  16. exports.DecoderBuffer = DecoderBuffer;
  17. DecoderBuffer.isDecoderBuffer = function isDecoderBuffer(data) {
  18. if (data instanceof DecoderBuffer) {
  19. return true;
  20. }
  21. // Or accept compatible API
  22. const isCompatible = typeof data === 'object' &&
  23. Buffer.isBuffer(data.base) &&
  24. data.constructor.name === 'DecoderBuffer' &&
  25. typeof data.offset === 'number' &&
  26. typeof data.length === 'number' &&
  27. typeof data.save === 'function' &&
  28. typeof data.restore === 'function' &&
  29. typeof data.isEmpty === 'function' &&
  30. typeof data.readUInt8 === 'function' &&
  31. typeof data.skip === 'function' &&
  32. typeof data.raw === 'function';
  33. return isCompatible;
  34. };
  35. DecoderBuffer.prototype.save = function save() {
  36. return { offset: this.offset, reporter: Reporter.prototype.save.call(this) };
  37. };
  38. DecoderBuffer.prototype.restore = function restore(save) {
  39. // Return skipped data
  40. const res = new DecoderBuffer(this.base);
  41. res.offset = save.offset;
  42. res.length = this.offset;
  43. this.offset = save.offset;
  44. Reporter.prototype.restore.call(this, save.reporter);
  45. return res;
  46. };
  47. DecoderBuffer.prototype.isEmpty = function isEmpty() {
  48. return this.offset === this.length;
  49. };
  50. DecoderBuffer.prototype.readUInt8 = function readUInt8(fail) {
  51. if (this.offset + 1 <= this.length)
  52. return this.base.readUInt8(this.offset++, true);
  53. else
  54. return this.error(fail || 'DecoderBuffer overrun');
  55. };
  56. DecoderBuffer.prototype.skip = function skip(bytes, fail) {
  57. if (!(this.offset + bytes <= this.length))
  58. return this.error(fail || 'DecoderBuffer overrun');
  59. const res = new DecoderBuffer(this.base);
  60. // Share reporter state
  61. res._reporterState = this._reporterState;
  62. res.offset = this.offset;
  63. res.length = this.offset + bytes;
  64. this.offset += bytes;
  65. return res;
  66. };
  67. DecoderBuffer.prototype.raw = function raw(save) {
  68. return this.base.slice(save ? save.offset : this.offset, this.length);
  69. };
  70. function EncoderBuffer(value, reporter) {
  71. if (Array.isArray(value)) {
  72. this.length = 0;
  73. this.value = value.map(function(item) {
  74. if (!EncoderBuffer.isEncoderBuffer(item))
  75. item = new EncoderBuffer(item, reporter);
  76. this.length += item.length;
  77. return item;
  78. }, this);
  79. } else if (typeof value === 'number') {
  80. if (!(0 <= value && value <= 0xff))
  81. return reporter.error('non-byte EncoderBuffer value');
  82. this.value = value;
  83. this.length = 1;
  84. } else if (typeof value === 'string') {
  85. this.value = value;
  86. this.length = Buffer.byteLength(value);
  87. } else if (Buffer.isBuffer(value)) {
  88. this.value = value;
  89. this.length = value.length;
  90. } else {
  91. return reporter.error('Unsupported type: ' + typeof value);
  92. }
  93. }
  94. exports.EncoderBuffer = EncoderBuffer;
  95. EncoderBuffer.isEncoderBuffer = function isEncoderBuffer(data) {
  96. if (data instanceof EncoderBuffer) {
  97. return true;
  98. }
  99. // Or accept compatible API
  100. const isCompatible = typeof data === 'object' &&
  101. data.constructor.name === 'EncoderBuffer' &&
  102. typeof data.length === 'number' &&
  103. typeof data.join === 'function';
  104. return isCompatible;
  105. };
  106. EncoderBuffer.prototype.join = function join(out, offset) {
  107. if (!out)
  108. out = Buffer.alloc(this.length);
  109. if (!offset)
  110. offset = 0;
  111. if (this.length === 0)
  112. return out;
  113. if (Array.isArray(this.value)) {
  114. this.value.forEach(function(item) {
  115. item.join(out, offset);
  116. offset += item.length;
  117. });
  118. } else {
  119. if (typeof this.value === 'number')
  120. out[offset] = this.value;
  121. else if (typeof this.value === 'string')
  122. out.write(this.value, offset);
  123. else if (Buffer.isBuffer(this.value))
  124. this.value.copy(out, offset);
  125. offset += this.length;
  126. }
  127. return out;
  128. };