encoder.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. var hpack = require('../hpack');
  2. var utils = hpack.utils;
  3. var huffman = hpack.huffman.encode;
  4. var assert = utils.assert;
  5. var WBuf = require('wbuf');
  6. function Encoder() {
  7. this.buffer = new WBuf();
  8. this.word = 0;
  9. this.bitOffset = 0;
  10. }
  11. module.exports = Encoder;
  12. Encoder.create = function create() {
  13. return new Encoder();
  14. };
  15. Encoder.prototype.render = function render() {
  16. return this.buffer.render();
  17. };
  18. Encoder.prototype.encodeBit = function encodeBit(bit) {
  19. var octet;
  20. this.word <<= 1;
  21. this.word |= bit;
  22. this.bitOffset++;
  23. if (this.bitOffset === 8) {
  24. this.buffer.writeUInt8(this.word);
  25. this.word = 0;
  26. this.bitOffset = 0;
  27. }
  28. };
  29. Encoder.prototype.encodeBits = function encodeBits(bits, len) {
  30. var left = bits;
  31. var leftLen = len;
  32. while (leftLen > 0) {
  33. var avail = Math.min(leftLen, 8 - this.bitOffset);
  34. var toWrite = left >>> (leftLen - avail);
  35. if (avail === 8) {
  36. this.buffer.writeUInt8(toWrite);
  37. } else {
  38. this.word <<= avail;
  39. this.word |= toWrite;
  40. this.bitOffset += avail;
  41. if (this.bitOffset === 8) {
  42. this.buffer.writeUInt8(this.word);
  43. this.word = 0;
  44. this.bitOffset = 0;
  45. }
  46. }
  47. leftLen -= avail;
  48. left &= (1 << leftLen) - 1;
  49. }
  50. };
  51. // Just for testing
  52. Encoder.prototype.skipBits = function skipBits(num) {
  53. this.bitOffset += num;
  54. this.buffer.skip(this.bitOffset >> 3);
  55. this.bitOffset &= 0x7;
  56. };
  57. Encoder.prototype.encodeInt = function encodeInt(num) {
  58. var prefix = 8 - this.bitOffset;
  59. // We are going to end up octet-aligned
  60. this.bitOffset = 0;
  61. var max = (1 << prefix) - 1;
  62. // Fast case - int fits into the prefix
  63. if (num < max) {
  64. this.buffer.writeUInt8((this.word << prefix) | num);
  65. return octet;
  66. }
  67. var left = num - max;
  68. this.buffer.writeUInt8((this.word << prefix) | max);
  69. do {
  70. var octet = left & 0x7f;
  71. left >>= 7;
  72. if (left !== 0)
  73. octet |= 0x80;
  74. this.buffer.writeUInt8(octet);
  75. } while (left !== 0);
  76. };
  77. Encoder.prototype.encodeStr = function encodeStr(value, isHuffman) {
  78. this.encodeBit(isHuffman ? 1 : 0);
  79. if (!isHuffman) {
  80. this.buffer.reserve(value.length + 1);
  81. this.encodeInt(value.length);
  82. for (var i = 0; i < value.length; i++)
  83. this.buffer.writeUInt8(value[i]);
  84. return;
  85. }
  86. var codes = [];
  87. var len = 0;
  88. var pad = 0;
  89. for (var i = 0; i < value.length; i++) {
  90. var code = huffman[value[i]];
  91. codes.push(code);
  92. len += code[0];
  93. }
  94. if (len % 8 !== 0)
  95. pad = 8 - (len % 8);
  96. len += pad;
  97. this.buffer.reserve((len / 8) + 1);
  98. this.encodeInt(len / 8);
  99. for (var i = 0; i < codes.length; i++) {
  100. var code = codes[i];
  101. this.encodeBits(code[1], code[0]);
  102. }
  103. // Append padding
  104. this.encodeBits(0xff >>> (8 - pad), pad);
  105. };