| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 | 
							- var hpack = require('../hpack');
 
- var utils = hpack.utils;
 
- var huffman = hpack.huffman.decode;
 
- var assert = utils.assert;
 
- var OffsetBuffer = require('obuf');
 
- function Decoder() {
 
-   this.buffer = new OffsetBuffer();
 
-   this.bitOffset = 0;
 
-   // Used internally in decodeStr
 
-   this._huffmanNode = null;
 
- }
 
- module.exports = Decoder;
 
- Decoder.create = function create() {
 
-   return new Decoder();
 
- };
 
- Decoder.prototype.isEmpty = function isEmpty() {
 
-   return this.buffer.isEmpty();
 
- };
 
- Decoder.prototype.push = function push(chunk) {
 
-   this.buffer.push(chunk);
 
- };
 
- Decoder.prototype.decodeBit = function decodeBit() {
 
-   // Need at least one octet
 
-   assert(this.buffer.has(1), 'Buffer too small for an int');
 
-   var octet;
 
-   var offset = this.bitOffset;
 
-   if (++this.bitOffset === 8) {
 
-     octet = this.buffer.readUInt8();
 
-     this.bitOffset = 0;
 
-   } else {
 
-     octet = this.buffer.peekUInt8();
 
-   }
 
-   return (octet >>> (7 - offset)) & 1;
 
- };
 
- // Just for testing
 
- Decoder.prototype.skipBits = function skipBits(n) {
 
-   this.bitOffset += n;
 
-   this.buffer.skip(this.bitOffset >> 3);
 
-   this.bitOffset &= 0x7;
 
- };
 
- Decoder.prototype.decodeInt = function decodeInt() {
 
-   // Need at least one octet
 
-   assert(this.buffer.has(1), 'Buffer too small for an int');
 
-   var prefix = 8 - this.bitOffset;
 
-   // We are going to end up octet-aligned
 
-   this.bitOffset = 0;
 
-   var max = (1 << prefix) - 1;
 
-   var octet = this.buffer.readUInt8() & max;
 
-   // Fast case - int fits into the prefix
 
-   if (octet !== max)
 
-     return octet;
 
-   // TODO(indutny): what about > 32bit numbers?
 
-   var res = 0;
 
-   var isLast = false;
 
-   var len = 0;
 
-   do {
 
-     octet = this.buffer.readUInt8();
 
-     isLast = (octet & 0x80) === 0;
 
-     res <<= 7;
 
-     res |= octet & 0x7f;
 
-     len++;
 
-   } while (!isLast);
 
-   assert(isLast, 'Incomplete data for multi-octet integer');
 
-   assert(len <= 4, 'Integer does not fit into 32 bits');
 
-   // Reverse bits
 
-   res = (res >>> 21) |
 
-         (((res >> 14) & 0x7f) << 7) |
 
-         (((res >> 7) & 0x7f) << 14) |
 
-         ((res & 0x7f) << 21);
 
-   res >>= (4 - len) * 7;
 
-   // Append prefix max
 
-   res += max;
 
-   return res;
 
- };
 
- Decoder.prototype.decodeHuffmanWord = function decodeHuffmanWord(input,
 
-                                                                  inputBits,
 
-                                                                  out) {
 
-   var root = huffman;
 
-   var node = this._huffmanNode;
 
-   var word = input;
 
-   var bits = inputBits;
 
-   for (; bits > 0; word &= (1 << bits) - 1) {
 
-     // Nudge the word bit length to match it
 
-     for (var i = Math.max(0, bits - 8); i < bits; i++) {
 
-       var subnode = node[word >>> i];
 
-       if (typeof subnode !== 'number') {
 
-         node = subnode;
 
-         bits = i;
 
-         break;
 
-       }
 
-       if (subnode === 0)
 
-         continue;
 
-       // Word bit length should match
 
-       if ((subnode >>> 9) !== bits - i) {
 
-         subnode = 0;
 
-         continue;
 
-       }
 
-       var octet = subnode & 0x1ff;
 
-       assert(octet !== 256, 'EOS in encoding');
 
-       out.push(octet);
 
-       node = root;
 
-       bits = i;
 
-       break;
 
-     }
 
-     if (subnode === 0)
 
-       break;
 
-   }
 
-   this._huffmanNode = node;
 
-   return bits;
 
- };
 
- Decoder.prototype.decodeStr = function decodeStr() {
 
-   var isHuffman = this.decodeBit();
 
-   var len = this.decodeInt();
 
-   assert(this.buffer.has(len), 'Not enough octets for string');
 
-   if (!isHuffman)
 
-     return this.buffer.take(len);
 
-   this._huffmanNode = huffman;
 
-   var out = [];
 
-   var word = 0;
 
-   var bits = 0;
 
-   var lastKey = 0;
 
-   for (var i = 0; i < len; i++) {
 
-     word <<= 8;
 
-     word |= this.buffer.readUInt8();
 
-     bits += 8;
 
-     bits = this.decodeHuffmanWord(word, bits, out);
 
-     lastKey = word >> bits;
 
-     word &= (1 << bits) - 1;
 
-   }
 
-   assert(this._huffmanNode === huffman, '8-bit EOS');
 
-   assert(word + 1 === (1 << bits), 'Final sequence is not EOS');
 
-   this._huffmanNode = null;
 
-   return out;
 
- };
 
 
  |