130 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			130 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
var hpack = require('../hpack');
 | 
						|
var utils = hpack.utils;
 | 
						|
var huffman = hpack.huffman.encode;
 | 
						|
var assert = utils.assert;
 | 
						|
 | 
						|
var WBuf = require('wbuf');
 | 
						|
 | 
						|
function Encoder() {
 | 
						|
  this.buffer = new WBuf();
 | 
						|
  this.word = 0;
 | 
						|
  this.bitOffset = 0;
 | 
						|
}
 | 
						|
module.exports = Encoder;
 | 
						|
 | 
						|
Encoder.create = function create() {
 | 
						|
  return new Encoder();
 | 
						|
};
 | 
						|
 | 
						|
Encoder.prototype.render = function render() {
 | 
						|
  return this.buffer.render();
 | 
						|
};
 | 
						|
 | 
						|
Encoder.prototype.encodeBit = function encodeBit(bit) {
 | 
						|
  var octet;
 | 
						|
 | 
						|
  this.word <<= 1;
 | 
						|
  this.word |= bit;
 | 
						|
  this.bitOffset++;
 | 
						|
 | 
						|
  if (this.bitOffset === 8) {
 | 
						|
    this.buffer.writeUInt8(this.word);
 | 
						|
    this.word = 0;
 | 
						|
    this.bitOffset = 0;
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
Encoder.prototype.encodeBits = function encodeBits(bits, len) {
 | 
						|
  var left = bits;
 | 
						|
  var leftLen = len;
 | 
						|
 | 
						|
  while (leftLen > 0) {
 | 
						|
    var avail = Math.min(leftLen, 8 - this.bitOffset);
 | 
						|
    var toWrite = left >>> (leftLen - avail);
 | 
						|
 | 
						|
    if (avail === 8) {
 | 
						|
      this.buffer.writeUInt8(toWrite);
 | 
						|
    } else {
 | 
						|
      this.word <<= avail;
 | 
						|
      this.word |= toWrite;
 | 
						|
      this.bitOffset += avail;
 | 
						|
      if (this.bitOffset === 8) {
 | 
						|
        this.buffer.writeUInt8(this.word);
 | 
						|
        this.word = 0;
 | 
						|
        this.bitOffset = 0;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    leftLen -= avail;
 | 
						|
    left &= (1 << leftLen) - 1;
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
// Just for testing
 | 
						|
Encoder.prototype.skipBits = function skipBits(num) {
 | 
						|
  this.bitOffset += num;
 | 
						|
  this.buffer.skip(this.bitOffset >> 3);
 | 
						|
  this.bitOffset &= 0x7;
 | 
						|
};
 | 
						|
 | 
						|
Encoder.prototype.encodeInt = function encodeInt(num) {
 | 
						|
  var prefix = 8 - this.bitOffset;
 | 
						|
 | 
						|
  // We are going to end up octet-aligned
 | 
						|
  this.bitOffset = 0;
 | 
						|
 | 
						|
  var max = (1 << prefix) - 1;
 | 
						|
 | 
						|
  // Fast case - int fits into the prefix
 | 
						|
  if (num < max) {
 | 
						|
    this.buffer.writeUInt8((this.word << prefix) | num);
 | 
						|
    return octet;
 | 
						|
  }
 | 
						|
 | 
						|
  var left = num - max;
 | 
						|
  this.buffer.writeUInt8((this.word << prefix) | max);
 | 
						|
  do {
 | 
						|
    var octet = left & 0x7f;
 | 
						|
    left >>= 7;
 | 
						|
    if (left !== 0)
 | 
						|
      octet |= 0x80;
 | 
						|
 | 
						|
    this.buffer.writeUInt8(octet);
 | 
						|
  } while (left !== 0);
 | 
						|
};
 | 
						|
 | 
						|
Encoder.prototype.encodeStr = function encodeStr(value, isHuffman) {
 | 
						|
  this.encodeBit(isHuffman ? 1 : 0);
 | 
						|
 | 
						|
  if (!isHuffman) {
 | 
						|
    this.buffer.reserve(value.length + 1);
 | 
						|
    this.encodeInt(value.length);
 | 
						|
    for (var i = 0; i < value.length; i++)
 | 
						|
      this.buffer.writeUInt8(value[i]);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  var codes = [];
 | 
						|
  var len = 0;
 | 
						|
  var pad = 0;
 | 
						|
 | 
						|
  for (var i = 0; i < value.length; i++) {
 | 
						|
    var code = huffman[value[i]];
 | 
						|
    codes.push(code);
 | 
						|
    len += code[0];
 | 
						|
  }
 | 
						|
  if (len % 8 !== 0)
 | 
						|
    pad = 8 - (len % 8);
 | 
						|
  len += pad;
 | 
						|
 | 
						|
  this.buffer.reserve((len / 8) + 1);
 | 
						|
  this.encodeInt(len / 8);
 | 
						|
  for (var i = 0; i < codes.length; i++) {
 | 
						|
    var code = codes[i];
 | 
						|
    this.encodeBits(code[1], code[0]);
 | 
						|
  }
 | 
						|
 | 
						|
  // Append padding
 | 
						|
  this.encodeBits(0xff >>> (8 - pad), pad);
 | 
						|
};
 |