1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/spdy/hpack_output_stream.h" 6 7 #include "base/logging.h" 8 9 10 namespace net { 11 12 using base::StringPiece; 13 using std::string; 14 15 HpackOutputStream::HpackOutputStream() 16 : bit_offset_(0) {} 17 18 HpackOutputStream::~HpackOutputStream() {} 19 20 void HpackOutputStream::AppendBits(uint8 bits, size_t bit_size) { 21 DCHECK_GT(bit_size, 0u); 22 DCHECK_LE(bit_size, 8u); 23 DCHECK_EQ(bits >> bit_size, 0); 24 size_t new_bit_offset = bit_offset_ + bit_size; 25 if (bit_offset_ == 0) { 26 // Buffer ends on a byte boundary. 27 DCHECK_LE(bit_size, 8u); 28 buffer_.append(1, bits << (8 - bit_size)); 29 } else if (new_bit_offset <= 8) { 30 // Buffer does not end on a byte boundary but the given bits fit 31 // in the remainder of the last byte. 32 *buffer_.rbegin() |= bits << (8 - new_bit_offset); 33 } else { 34 // Buffer does not end on a byte boundary and the given bits do 35 // not fit in the remainder of the last byte. 36 *buffer_.rbegin() |= bits >> (new_bit_offset - 8); 37 buffer_.append(1, bits << (16 - new_bit_offset)); 38 } 39 bit_offset_ = new_bit_offset % 8; 40 } 41 42 void HpackOutputStream::AppendPrefix(HpackPrefix prefix) { 43 AppendBits(prefix.bits, prefix.bit_size); 44 } 45 46 void HpackOutputStream::AppendBytes(StringPiece buffer) { 47 DCHECK_EQ(bit_offset_, 0u); 48 buffer_.append(buffer.data(), buffer.size()); 49 } 50 51 void HpackOutputStream::AppendUint32(uint32 I) { 52 // The algorithm below is adapted from the pseudocode in 6.1. 53 size_t N = 8 - bit_offset_; 54 uint8 max_first_byte = static_cast<uint8>((1 << N) - 1); 55 if (I < max_first_byte) { 56 AppendBits(static_cast<uint8>(I), N); 57 } else { 58 AppendBits(max_first_byte, N); 59 I -= max_first_byte; 60 while ((I & ~0x7f) != 0) { 61 buffer_.append(1, (I & 0x7f) | 0x80); 62 I >>= 7; 63 } 64 AppendBits(static_cast<uint8>(I), 8); 65 } 66 } 67 68 void HpackOutputStream::TakeString(string* output) { 69 // This must hold, since all public functions cause the buffer to 70 // end on a byte boundary. 71 DCHECK_EQ(bit_offset_, 0u); 72 buffer_.swap(*output); 73 buffer_.clear(); 74 bit_offset_ = 0; 75 } 76 77 } // namespace net 78