/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef THRIFT2_PROTOCOL_TBINARYPROTOCOL_TCC_ #define THRIFT2_PROTOCOL_TBINARYPROTOCOL_TCC_ 1 #include #include namespace apache { namespace thrift { inline uint32_t BinaryProtocolWriter::writeMessageBegin( folly::StringPiece name, MessageType messageType, int32_t seqid) { int32_t version = (VERSION_1) | ((int32_t)messageType); uint32_t wsize = 0; wsize += writeI32(version); wsize += writeString(name); wsize += writeI32(seqid); return wsize; } inline uint32_t BinaryProtocolWriter::writeMessageEnd() { return 0; } inline uint32_t BinaryProtocolWriter::writeStructBegin(const char* /*name*/) { descend(); return 0; } inline uint32_t BinaryProtocolWriter::writeStructEnd() { ascend(); return 0; } inline uint32_t BinaryProtocolWriter::writeFieldBegin( const char* /*name*/, TType fieldType, int16_t fieldId) { uint32_t wsize = 0; wsize += writeByte((int8_t)fieldType); wsize += writeI16(fieldId); return wsize; } inline uint32_t BinaryProtocolWriter::writeFieldEnd() { return 0; } inline uint32_t BinaryProtocolWriter::writeFieldStop() { return writeByte((int8_t)TType::T_STOP); } inline uint32_t BinaryProtocolWriter::writeMapBegin( const TType keyType, TType valType, uint32_t size) { descend(); uint32_t wsize = 0; wsize += writeByte((int8_t)keyType); wsize += writeByte((int8_t)valType); wsize += writeI32((int32_t)size); return wsize; } inline uint32_t BinaryProtocolWriter::writeMapEnd() { ascend(); return 0; } inline uint32_t BinaryProtocolWriter::writeListBegin( TType elemType, uint32_t size) { descend(); uint32_t wsize = 0; wsize += writeByte((int8_t)elemType); wsize += writeI32((int32_t)size); return wsize; } inline uint32_t BinaryProtocolWriter::writeListEnd() { ascend(); return 0; } inline uint32_t BinaryProtocolWriter::writeSetBegin( TType elemType, uint32_t size) { descend(); uint32_t wsize = 0; wsize += writeByte((int8_t)elemType); wsize += writeI32((int32_t)size); return wsize; } inline uint32_t BinaryProtocolWriter::writeSetEnd() { ascend(); return 0; } inline uint32_t BinaryProtocolWriter::writeBool(bool value) { out_.write(detail::validate_bool(value)); return sizeof(value); } inline uint32_t BinaryProtocolWriter::writeByte(int8_t byte) { out_.write(byte); return sizeof(byte); } inline uint32_t BinaryProtocolWriter::writeI16(int16_t i16) { out_.writeBE(i16); return sizeof(i16); } inline uint32_t BinaryProtocolWriter::writeI32(int32_t i32) { out_.writeBE(i32); return sizeof(i32); } inline uint32_t BinaryProtocolWriter::writeI64(int64_t i64) { out_.writeBE(i64); return sizeof(i64); } inline uint32_t BinaryProtocolWriter::writeDouble(double dub) { static_assert(sizeof(double) == sizeof(uint64_t), ""); static_assert(std::numeric_limits::is_iec559, ""); uint64_t bits = folly::bit_cast(dub); out_.writeBE(bits); return sizeof(bits); } inline uint32_t BinaryProtocolWriter::writeFloat(float flt) { static_assert(sizeof(float) == sizeof(uint32_t), ""); static_assert(std::numeric_limits::is_iec559, ""); uint32_t bits = folly::bit_cast(flt); out_.writeBE(bits); return sizeof(bits); } inline uint32_t BinaryProtocolWriter::writeString(folly::StringPiece str) { return writeBinary(str); } inline uint32_t BinaryProtocolWriter::writeBinary(folly::StringPiece str) { return writeBinary(folly::ByteRange(str)); } inline uint32_t BinaryProtocolWriter::writeBinary(folly::ByteRange v) { auto size = v.size(); checkBinarySize(size); uint32_t result = writeI32((int32_t)size); out_.push(v.data(), size); return static_cast(result + size); } inline uint32_t BinaryProtocolWriter::writeBinary( const std::unique_ptr& str) { if (!str) { return writeI32(0); } return writeBinary(*str); } inline uint32_t BinaryProtocolWriter::writeBinary(const folly::IOBuf& str) { return writeBinaryImpl(str); } inline uint32_t BinaryProtocolWriter::writeRaw(const folly::IOBuf& str) { return writeBinaryImpl(str); } inline void BinaryProtocolWriter::checkBinarySize(uint64_t size) { // We can't deserialize binary/string over 2GB, enforcing the same limit on // serializing for consistency constexpr uint64_t limit = std::numeric_limits::max(); if (size > limit) { TProtocolException::throwExceededSizeLimit(size, limit); } } template inline uint32_t BinaryProtocolWriter::writeBinaryImpl(const folly::IOBuf& str) { size_t size = str.computeChainDataLength(); checkBinarySize(size); uint32_t result = kWriteSize ? writeI32((int32_t)size) : 0; if (sharing_ != SHARE_EXTERNAL_BUFFER && !str.isManaged()) { const auto growth = size - out_.length(); for (folly::ByteRange buf : str) { const auto tailroom = out_.length(); if (tailroom < buf.size()) { out_.push(buf.uncheckedSubpiece(0, tailroom)); buf.uncheckedAdvance(tailroom); out_.ensure(growth); } out_.push(buf); } } else { out_.insert(str); } return result + static_cast(size); } inline void BinaryProtocolWriter::rewriteDouble(double dub, int64_t offset) { auto cursor = out_.tail(offset); cursor.writeBE(folly::bit_cast(dub)); } inline folly::io::Cursor BinaryProtocolWriter::tail(size_t n) { auto cursor = out_.tail(n); return {cursor, n}; } /** * Functions that return the serialized size */ inline uint32_t BinaryProtocolWriter::serializedMessageSize( folly::StringPiece name) const { // I32{version} + String{name} + I32{seqid} return 2 * serializedSizeI32() + serializedSizeString(name); } inline uint32_t BinaryProtocolWriter::serializedFieldSize( const char* /*name*/, TType /*fieldType*/, int16_t /*fieldId*/) const { // byte + I16 return serializedSizeByte() + serializedSizeI16(); } inline uint32_t BinaryProtocolWriter::serializedStructSize(const char* /*name*/ ) const { return 0; } inline uint32_t BinaryProtocolWriter::serializedSizeMapBegin( TType /*keyType*/, TType /*valType*/, uint32_t /*size*/) const { return serializedSizeByte() + serializedSizeByte() + serializedSizeI32(); } inline uint32_t BinaryProtocolWriter::serializedSizeMapEnd() const { return 0; } inline uint32_t BinaryProtocolWriter::serializedSizeListBegin( TType /*elemType*/, uint32_t /*size*/ ) const { return serializedSizeByte() + serializedSizeI32(); } inline uint32_t BinaryProtocolWriter::serializedSizeListEnd() const { return 0; } inline uint32_t BinaryProtocolWriter::serializedSizeSetBegin( TType /*elemType*/, uint32_t /*size*/) const { return serializedSizeByte() + serializedSizeI32(); } inline uint32_t BinaryProtocolWriter::serializedSizeSetEnd() const { return 0; } inline uint32_t BinaryProtocolWriter::serializedSizeStop() const { return 1; } inline uint32_t BinaryProtocolWriter::serializedSizeBool(bool /*val*/) const { return 1; } inline uint32_t BinaryProtocolWriter::serializedSizeByte(int8_t /*val*/) const { return 1; } inline uint32_t BinaryProtocolWriter::serializedSizeI16(int16_t /*val*/) const { return 2; } inline uint32_t BinaryProtocolWriter::serializedSizeI32(int32_t /*val*/) const { return 4; } inline uint32_t BinaryProtocolWriter::serializedSizeI64(int64_t /*val*/) const { return 8; } inline uint32_t BinaryProtocolWriter::serializedSizeDouble( double /*val*/) const { return 8; } inline uint32_t BinaryProtocolWriter::serializedSizeFloat(float /*val*/) const { return 4; } inline uint32_t BinaryProtocolWriter::serializedSizeString( folly::StringPiece str) const { return serializedSizeBinary(str); } inline uint32_t BinaryProtocolWriter::serializedSizeBinary( folly::StringPiece str) const { return serializedSizeBinary(folly::ByteRange(str)); } inline uint32_t BinaryProtocolWriter::serializedSizeBinary( folly::ByteRange str) const { // I32{length of string} + binary{string contents} return serializedSizeI32() + static_cast(str.size()); } inline uint32_t BinaryProtocolWriter::serializedSizeBinary( const std::unique_ptr& v) const { return v ? serializedSizeBinary(*v) : 0; } inline uint32_t BinaryProtocolWriter::serializedSizeBinary( const folly::IOBuf& v) const { size_t size = v.computeChainDataLength(); uint32_t limit = std::numeric_limits::max() - serializedSizeI32(); if (size > limit) { TProtocolException::throwExceededSizeLimit(size, limit); } return serializedSizeI32() + static_cast(size); } inline uint32_t BinaryProtocolWriter::serializedSizeZCBinary( folly::StringPiece str) const { return serializedSizeZCBinary(folly::ByteRange(str)); } inline uint32_t BinaryProtocolWriter::serializedSizeZCBinary( folly::ByteRange v) const { return serializedSizeBinary(v); } inline uint32_t BinaryProtocolWriter::serializedSizeZCBinary( const std::unique_ptr& v) const { return v ? serializedSizeZCBinary(*v) : 0; } inline uint32_t BinaryProtocolWriter::serializedSizeZCBinary( const folly::IOBuf& v) const { size_t size = v.computeChainDataLength(); return (size > folly::IOBufQueue::kMaxPackCopy) ? serializedSizeI32() // too big to pack: size only : static_cast(size) + serializedSizeI32(); // size + packed data } /** * Reading functions */ inline void BinaryProtocolReader::readMessageBegin( std::string& name, MessageType& messageType, int32_t& seqid) { int32_t sz; readI32(sz); if (sz < 0) { // Check for correct version number int32_t version = sz & VERSION_MASK; if (version != VERSION_1) { throwBadVersionIdentifier(sz); } messageType = (MessageType)(sz & 0x000000ff); readString(name); readI32(seqid); } else { if (this->strict_read_) { throwMissingVersionIdentifier(sz); } else { // Handle pre-versioned input int8_t type; readStringBody(name, sz); readByte(type); messageType = (MessageType)type; readI32(seqid); } } } inline void BinaryProtocolReader::readMessageEnd() {} inline void BinaryProtocolReader::readStructBegin(std::string& name) { descend(); if (!name.empty()) { name.clear(); } } inline void BinaryProtocolReader::readStructEnd() { ascend(); } inline void BinaryProtocolReader::readFieldBegin( std::string& /*name*/, TType& fieldType, int16_t& fieldId) { int8_t type; readByte(type); fieldType = (TType)type; if (fieldType == TType::T_STOP) { fieldId = 0; return; } readI16(fieldId); } inline void BinaryProtocolReader::readFieldEnd() {} inline void BinaryProtocolReader::readMapBegin( TType& keyType, TType& valType, uint32_t& size) { descend(); int8_t k, v; int32_t sizei; readByte(k); keyType = (TType)k; readByte(v); valType = (TType)v; readI32(sizei); checkContainerSize(sizei); size = (uint32_t)sizei; } inline void BinaryProtocolReader::readMapEnd() { ascend(); } inline void BinaryProtocolReader::readListBegin( TType& elemType, uint32_t& size) { descend(); int8_t e; int32_t sizei; readByte(e); elemType = (TType)e; readI32(sizei); checkContainerSize(sizei); size = (uint32_t)sizei; } inline void BinaryProtocolReader::readListEnd() { ascend(); } inline void BinaryProtocolReader::readSetBegin( TType& elemType, uint32_t& size) { descend(); int8_t e; int32_t sizei; readByte(e); elemType = (TType)e; readI32(sizei); checkContainerSize(sizei); size = (uint32_t)sizei; } inline void BinaryProtocolReader::readSetEnd() { ascend(); } inline void BinaryProtocolReader::readBool(bool& value) { auto byte = in_.read(); if (byte >= 2) { TProtocolException::throwBoolValueOutOfRange(byte); } value = static_cast(byte); } inline void BinaryProtocolReader::readBool(std::vector::reference value) { bool ret = false; readBool(ret); value = ret; } inline void BinaryProtocolReader::readByte(int8_t& byte) { byte = in_.read(); } inline void BinaryProtocolReader::readI16(int16_t& i16) { i16 = in_.readBE(); } inline void BinaryProtocolReader::readI32(int32_t& i32) { i32 = in_.readBE(); } inline void BinaryProtocolReader::readI64(int64_t& i64) { i64 = in_.readBE(); } inline void BinaryProtocolReader::readDouble(double& dub) { static_assert(sizeof(double) == sizeof(uint64_t), ""); static_assert(std::numeric_limits::is_iec559, ""); uint64_t bits = in_.readBE(); dub = folly::bit_cast(bits); } inline void BinaryProtocolReader::readFloat(float& flt) { static_assert(sizeof(float) == sizeof(uint32_t), ""); static_assert(std::numeric_limits::is_iec559, ""); uint32_t bits = in_.readBE(); flt = folly::bit_cast(bits); } inline void BinaryProtocolReader::checkStringSize(int32_t size) { // Catch error cases if (size < 0) { TProtocolException::throwNegativeSize(); } if (string_limit_ > 0 && size > string_limit_) { TProtocolException::throwExceededSizeLimit(size, string_limit_); } } inline void BinaryProtocolReader::checkContainerSize(int32_t size) { if (size < 0) { TProtocolException::throwNegativeSize(); } else if (container_limit_ && size > container_limit_) { TProtocolException::throwExceededSizeLimit(size, container_limit_); } } template inline void BinaryProtocolReader::readString(StrType& str) { int32_t size; readI32(size); readStringBody(str, size); } template inline void BinaryProtocolReader::readBinary(StrType& str) { readString(str); } inline void BinaryProtocolReader::readBinary( std::unique_ptr& str) { if (!str) { str = std::make_unique(); } readBinary(*str); } inline void BinaryProtocolReader::readBinary(folly::IOBuf& str) { int32_t size; readI32(size); checkStringSize(size); in_.clone(str, size); if (sharing_ != SHARE_EXTERNAL_BUFFER && !str.isManaged()) { str = str.cloneCoalescedAsValueWithHeadroomTailroom(0, 0); str.makeManaged(); } } template inline void BinaryProtocolReader::readStringBody(StrType& str, int32_t size) { checkStringSize(size); // Catch empty string case if (size == 0) { str.clear(); return; } if (static_cast(in_.length()) < size) { if (!in_.canAdvance(size)) { protocol::TProtocolException::throwTruncatedData(); } str.reserve(size); // only reserve for multi iter case below } str.clear(); size_t size_left = size; while (size_left > 0) { auto data = in_.peekBytes(); auto data_avail = std::min(data.size(), size_left); if (data.empty()) { TProtocolException::throwTruncatedData(); } str.append((const char*)data.data(), data_avail); size_left -= data_avail; in_.skipNoAdvance(data_avail); } } inline bool BinaryProtocolReader::advanceToNextField( int16_t nextFieldId, TType nextFieldType, StructReadState& state) { if (nextFieldType == TType::T_STOP) { if (in_.length() && *in_.data() == TType::T_STOP) { in_.skipNoAdvance(1); return true; } } else { if (in_.length() >= 3) { uint8_t type = *in_.data(); if (nextFieldType == type) { int16_t fieldId = folly::Endian::big(folly::loadUnaligned(in_.data() + 1)); in_.skipNoAdvance(3); if (nextFieldId == fieldId) { return true; } state.fieldType = (TType)type; state.fieldId = fieldId; return false; } state.fieldType = (TType)type; if (type != TType::T_STOP) { state.fieldId = folly::Endian::big(folly::loadUnaligned(in_.data() + 1)); in_.skipNoAdvance(3); } else { in_.skipNoAdvance(1); } return false; } } state.readFieldBeginNoInline(this); return false; } inline void BinaryProtocolReader::readFieldBeginWithState( StructReadState& state) { int8_t type; readByte(type); state.fieldType = (TType)type; if (state.fieldType == TType::T_STOP) { return; } readI16(state.fieldId); } constexpr std::size_t BinaryProtocolReader::fixedSizeInContainer(TType type) { switch (type) { case TType::T_BOOL: case TType::T_BYTE: return 1; case TType::T_I16: return 2; case TType::T_I32: case TType::T_FLOAT: return 4; case TType::T_I64: case TType::T_DOUBLE: return 8; default: return 0; } } } // namespace thrift } // namespace apache #endif // #ifndef THRIFT2_PROTOCOL_TBINARYPROTOCOL_TCC_