|  | // Copyright 2016 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "quiche/http2/decoder/decode_buffer.h" | 
|  |  | 
|  | namespace http2 { | 
|  |  | 
|  | uint8_t DecodeBuffer::DecodeUInt8() { | 
|  | return static_cast<uint8_t>(DecodeChar()); | 
|  | } | 
|  |  | 
|  | uint16_t DecodeBuffer::DecodeUInt16() { | 
|  | QUICHE_DCHECK_LE(2u, Remaining()); | 
|  | const uint8_t b1 = DecodeUInt8(); | 
|  | const uint8_t b2 = DecodeUInt8(); | 
|  | // Note that chars are automatically promoted to ints during arithmetic, | 
|  | // so the b1 << 8 doesn't end up as zero before being or-ed with b2. | 
|  | // And the left-shift operator has higher precedence than the or operator. | 
|  | return b1 << 8 | b2; | 
|  | } | 
|  |  | 
|  | uint32_t DecodeBuffer::DecodeUInt24() { | 
|  | QUICHE_DCHECK_LE(3u, Remaining()); | 
|  | const uint8_t b1 = DecodeUInt8(); | 
|  | const uint8_t b2 = DecodeUInt8(); | 
|  | const uint8_t b3 = DecodeUInt8(); | 
|  | return b1 << 16 | b2 << 8 | b3; | 
|  | } | 
|  |  | 
|  | uint32_t DecodeBuffer::DecodeUInt31() { | 
|  | QUICHE_DCHECK_LE(4u, Remaining()); | 
|  | const uint8_t b1 = DecodeUInt8() & 0x7f;  // Mask out the high order bit. | 
|  | const uint8_t b2 = DecodeUInt8(); | 
|  | const uint8_t b3 = DecodeUInt8(); | 
|  | const uint8_t b4 = DecodeUInt8(); | 
|  | return b1 << 24 | b2 << 16 | b3 << 8 | b4; | 
|  | } | 
|  |  | 
|  | uint32_t DecodeBuffer::DecodeUInt32() { | 
|  | QUICHE_DCHECK_LE(4u, Remaining()); | 
|  | const uint8_t b1 = DecodeUInt8(); | 
|  | const uint8_t b2 = DecodeUInt8(); | 
|  | const uint8_t b3 = DecodeUInt8(); | 
|  | const uint8_t b4 = DecodeUInt8(); | 
|  | return b1 << 24 | b2 << 16 | b3 << 8 | b4; | 
|  | } | 
|  |  | 
|  | #ifndef NDEBUG | 
|  | void DecodeBuffer::set_subset_of_base(DecodeBuffer* base, | 
|  | const DecodeBufferSubset* subset) { | 
|  | QUICHE_DCHECK_EQ(this, subset); | 
|  | base->set_subset(subset); | 
|  | } | 
|  | void DecodeBuffer::clear_subset_of_base(DecodeBuffer* base, | 
|  | const DecodeBufferSubset* subset) { | 
|  | QUICHE_DCHECK_EQ(this, subset); | 
|  | base->clear_subset(subset); | 
|  | } | 
|  | void DecodeBuffer::set_subset(const DecodeBufferSubset* subset) { | 
|  | QUICHE_DCHECK(subset != nullptr); | 
|  | QUICHE_DCHECK_EQ(subset_, nullptr) << "There is already a subset"; | 
|  | subset_ = subset; | 
|  | } | 
|  | void DecodeBuffer::clear_subset(const DecodeBufferSubset* subset) { | 
|  | QUICHE_DCHECK(subset != nullptr); | 
|  | QUICHE_DCHECK_EQ(subset_, subset); | 
|  | subset_ = nullptr; | 
|  | } | 
|  | void DecodeBufferSubset::DebugSetup() { | 
|  | start_base_offset_ = base_buffer_->Offset(); | 
|  | max_base_offset_ = start_base_offset_ + FullSize(); | 
|  | QUICHE_DCHECK_LE(max_base_offset_, base_buffer_->FullSize()); | 
|  |  | 
|  | // Ensure that there is only one DecodeBufferSubset at a time for a base. | 
|  | set_subset_of_base(base_buffer_, this); | 
|  | } | 
|  | void DecodeBufferSubset::DebugTearDown() { | 
|  | // Ensure that the base hasn't been modified. | 
|  | QUICHE_DCHECK_EQ(start_base_offset_, base_buffer_->Offset()) | 
|  | << "The base buffer was modified"; | 
|  |  | 
|  | // Ensure that we haven't gone beyond the maximum allowed offset. | 
|  | size_t offset = Offset(); | 
|  | QUICHE_DCHECK_LE(offset, FullSize()); | 
|  | QUICHE_DCHECK_LE(start_base_offset_ + offset, max_base_offset_); | 
|  | QUICHE_DCHECK_LE(max_base_offset_, base_buffer_->FullSize()); | 
|  |  | 
|  | clear_subset_of_base(base_buffer_, this); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | }  // namespace http2 |