// Copyright (c) 2012 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 "net/quic/quic_data_writer.h" #include <algorithm> #include <limits> #include <string> #include "base/basictypes.h" #include "base/logging.h" using base::StringPiece; using std::numeric_limits; namespace net { QuicDataWriter::QuicDataWriter(size_t size) : buffer_(new char[size]), capacity_(size), length_(0) { } QuicDataWriter::~QuicDataWriter() { delete[] buffer_; } char* QuicDataWriter::take() { char* rv = buffer_; buffer_ = NULL; capacity_ = 0; length_ = 0; return rv; } bool QuicDataWriter::WriteUInt8(uint8 value) { return WriteBytes(&value, sizeof(value)); } bool QuicDataWriter::WriteUInt16(uint16 value) { return WriteBytes(&value, sizeof(value)); } bool QuicDataWriter::WriteUInt32(uint32 value) { return WriteBytes(&value, sizeof(value)); } bool QuicDataWriter::WriteUInt48(uint64 value) { uint32 hi = value >> 32; uint32 lo = value & GG_UINT64_C(0x00000000FFFFFFFF); return WriteUInt32(lo) && WriteUInt16(hi); } bool QuicDataWriter::WriteUInt64(uint64 value) { return WriteBytes(&value, sizeof(value)); } bool QuicDataWriter::WriteUFloat16(uint64 value) { uint16 result; if (value < (GG_UINT64_C(1) << kUFloat16MantissaEffectiveBits)) { // Fast path: either the value is denormalized, or has exponent zero. // Both cases are represented by the value itself. result = value; } else if (value >= kUFloat16MaxValue) { // Value is out of range; clamp it to the maximum representable. result = numeric_limits<uint16>::max(); } else { // The highest bit is between position 13 and 42 (zero-based), which // corresponds to exponent 1-30. In the output, mantissa is from 0 to 10, // hidden bit is 11 and exponent is 11 to 15. Shift the highest bit to 11 // and count the shifts. uint16 exponent = 0; for (uint16 offset = 16; offset > 0; offset /= 2) { // Right-shift the value until the highest bit is in position 11. // For offset of 16, 8, 4, 2 and 1 (binary search over 1-30), // shift if the bit is at or above 11 + offset. if (value >= (GG_UINT64_C(1) << (kUFloat16MantissaBits + offset))) { exponent += offset; value >>= offset; } } DCHECK_GE(exponent, 1); DCHECK_LE(exponent, kUFloat16MaxExponent); DCHECK_GE(value, GG_UINT64_C(1) << kUFloat16MantissaBits); DCHECK_LT(value, GG_UINT64_C(1) << kUFloat16MantissaEffectiveBits); // Hidden bit (position 11) is set. We should remove it and increment the // exponent. Equivalently, we just add it to the exponent. // This hides the bit. result = value + (exponent << kUFloat16MantissaBits); } return WriteBytes(&result, sizeof(result)); } bool QuicDataWriter::WriteStringPiece16(StringPiece val) { if (val.length() > numeric_limits<uint16>::max()) { return false; } if (!WriteUInt16(val.size())) { return false; } return WriteBytes(val.data(), val.size()); } bool QuicDataWriter::WriteIOVector(const IOVector& data) { char *dest = BeginWrite(data.TotalBufferSize()); if (!dest) { return false; } for (size_t i = 0; i < data.Size(); ++i) { WriteBytes(data.iovec()[i].iov_base, data.iovec()[i].iov_len); } return true; } char* QuicDataWriter::BeginWrite(size_t length) { if (length_ > capacity_) { return NULL; } if (capacity_ - length_ < length) { return NULL; } #ifdef ARCH_CPU_64_BITS DCHECK_LE(length, numeric_limits<uint32>::max()); #endif return buffer_ + length_; } bool QuicDataWriter::WriteBytes(const void* data, size_t data_len) { char* dest = BeginWrite(data_len); if (!dest) { return false; } memcpy(dest, data, data_len); length_ += data_len; return true; } bool QuicDataWriter::WriteRepeatedByte(uint8 byte, size_t count) { char* dest = BeginWrite(count); if (!dest) { return false; } memset(dest, byte, count); length_ += count; return true; } void QuicDataWriter::WritePadding() { DCHECK_LE(length_, capacity_); if (length_ > capacity_) { return; } memset(buffer_ + length_, 0x00, capacity_ - length_); length_ = capacity_; } bool QuicDataWriter::WriteUInt8ToOffset(uint8 value, size_t offset) { if (offset >= capacity_) { LOG(DFATAL) << "offset: " << offset << " >= capacity: " << capacity_; return false; } size_t latched_length = length_; length_ = offset; bool success = WriteUInt8(value); DCHECK_LE(length_, latched_length); length_ = latched_length; return success; } bool QuicDataWriter::WriteUInt32ToOffset(uint32 value, size_t offset) { DCHECK_LT(offset, capacity_); size_t latched_length = length_; length_ = offset; bool success = WriteUInt32(value); DCHECK_LE(length_, latched_length); length_ = latched_length; return success; } bool QuicDataWriter::WriteUInt48ToOffset(uint64 value, size_t offset) { DCHECK_LT(offset, capacity_); size_t latched_length = length_; length_ = offset; bool success = WriteUInt48(value); DCHECK_LE(length_, latched_length); length_ = latched_length; return success; } } // namespace net