Warning, /include/thrift/protocol/TCompactProtocol.tcc is written in an unsupported language. File is not indexed.
0001 /*
0002 * Licensed to the Apache Software Foundation (ASF) under one
0003 * or more contributor license agreements. See the NOTICE file
0004 * distributed with this work for additional information
0005 * regarding copyright ownership. The ASF licenses this file
0006 * to you under the Apache License, Version 2.0 (the
0007 * "License"); you may not use this file except in compliance
0008 * with the License. You may obtain a copy of the License at
0009 *
0010 * http://www.apache.org/licenses/LICENSE-2.0
0011 *
0012 * Unless required by applicable law or agreed to in writing,
0013 * software distributed under the License is distributed on an
0014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0015 * KIND, either express or implied. See the License for the
0016 * specific language governing permissions and limitations
0017 * under the License.
0018 */
0019 #ifndef _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_TCC_
0020 #define _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_TCC_ 1
0021
0022 #include <limits>
0023 #include <cstdlib>
0024
0025 #include "thrift/config.h"
0026
0027 /*
0028 * TCompactProtocol::i*ToZigzag depend on the fact that the right shift
0029 * operator on a signed integer is an arithmetic (sign-extending) shift.
0030 * If this is not the case, the current implementation will not work.
0031 * If anyone encounters this error, we can try to figure out the best
0032 * way to implement an arithmetic right shift on their platform.
0033 */
0034 #if !defined(SIGNED_RIGHT_SHIFT_IS) || !defined(ARITHMETIC_RIGHT_SHIFT)
0035 # error "Unable to determine the behavior of a signed right shift"
0036 #endif
0037 #if SIGNED_RIGHT_SHIFT_IS != ARITHMETIC_RIGHT_SHIFT
0038 # error "TCompactProtocol currently only works if a signed right shift is arithmetic"
0039 #endif
0040
0041 #ifdef __GNUC__
0042 #define UNLIKELY(val) (__builtin_expect((val), 0))
0043 #else
0044 #define UNLIKELY(val) (val)
0045 #endif
0046
0047 namespace apache { namespace thrift { namespace protocol {
0048
0049 namespace detail { namespace compact {
0050
0051 enum Types {
0052 CT_STOP = 0x00,
0053 CT_BOOLEAN_TRUE = 0x01,
0054 CT_BOOLEAN_FALSE = 0x02,
0055 CT_BYTE = 0x03,
0056 CT_I16 = 0x04,
0057 CT_I32 = 0x05,
0058 CT_I64 = 0x06,
0059 CT_DOUBLE = 0x07,
0060 CT_BINARY = 0x08,
0061 CT_LIST = 0x09,
0062 CT_SET = 0x0A,
0063 CT_MAP = 0x0B,
0064 CT_STRUCT = 0x0C
0065 };
0066
0067 const int8_t TTypeToCType[16] = {
0068 CT_STOP, // T_STOP
0069 0, // unused
0070 CT_BOOLEAN_TRUE, // T_BOOL
0071 CT_BYTE, // T_BYTE
0072 CT_DOUBLE, // T_DOUBLE
0073 0, // unused
0074 CT_I16, // T_I16
0075 0, // unused
0076 CT_I32, // T_I32
0077 0, // unused
0078 CT_I64, // T_I64
0079 CT_BINARY, // T_STRING
0080 CT_STRUCT, // T_STRUCT
0081 CT_MAP, // T_MAP
0082 CT_SET, // T_SET
0083 CT_LIST, // T_LIST
0084 };
0085
0086 }} // end detail::compact namespace
0087
0088
0089 template <class Transport_>
0090 uint32_t TCompactProtocolT<Transport_>::writeMessageBegin(
0091 const std::string& name,
0092 const TMessageType messageType,
0093 const int32_t seqid) {
0094 uint32_t wsize = 0;
0095 wsize += writeByte(PROTOCOL_ID);
0096 wsize += writeByte((VERSION_N & VERSION_MASK) | (((int32_t)messageType << TYPE_SHIFT_AMOUNT) & TYPE_MASK));
0097 wsize += writeVarint32(seqid);
0098 wsize += writeString(name);
0099 return wsize;
0100 }
0101
0102 /**
0103 * Write a field header containing the field id and field type. If the
0104 * difference between the current field id and the last one is small (< 15),
0105 * then the field id will be encoded in the 4 MSB as a delta. Otherwise, the
0106 * field id will follow the type header as a zigzag varint.
0107 */
0108 template <class Transport_>
0109 uint32_t TCompactProtocolT<Transport_>::writeFieldBegin(const char* name,
0110 const TType fieldType,
0111 const int16_t fieldId) {
0112 if (fieldType == T_BOOL) {
0113 booleanField_.name = name;
0114 booleanField_.fieldType = fieldType;
0115 booleanField_.fieldId = fieldId;
0116 } else {
0117 return writeFieldBeginInternal(name, fieldType, fieldId, -1);
0118 }
0119 return 0;
0120 }
0121
0122 /**
0123 * Write the STOP symbol so we know there are no more fields in this struct.
0124 */
0125 template <class Transport_>
0126 uint32_t TCompactProtocolT<Transport_>::writeFieldStop() {
0127 return writeByte(T_STOP);
0128 }
0129
0130 /**
0131 * Write a struct begin. This doesn't actually put anything on the wire. We
0132 * use it as an opportunity to put special placeholder markers on the field
0133 * stack so we can get the field id deltas correct.
0134 */
0135 template <class Transport_>
0136 uint32_t TCompactProtocolT<Transport_>::writeStructBegin(const char* name) {
0137 (void) name;
0138 lastField_.push(lastFieldId_);
0139 lastFieldId_ = 0;
0140 return 0;
0141 }
0142
0143 /**
0144 * Write a struct end. This doesn't actually put anything on the wire. We use
0145 * this as an opportunity to pop the last field from the current struct off
0146 * of the field stack.
0147 */
0148 template <class Transport_>
0149 uint32_t TCompactProtocolT<Transport_>::writeStructEnd() {
0150 lastFieldId_ = lastField_.top();
0151 lastField_.pop();
0152 return 0;
0153 }
0154
0155 /**
0156 * Write a List header.
0157 */
0158 template <class Transport_>
0159 uint32_t TCompactProtocolT<Transport_>::writeListBegin(const TType elemType,
0160 const uint32_t size) {
0161 return writeCollectionBegin(elemType, size);
0162 }
0163
0164 /**
0165 * Write a set header.
0166 */
0167 template <class Transport_>
0168 uint32_t TCompactProtocolT<Transport_>::writeSetBegin(const TType elemType,
0169 const uint32_t size) {
0170 return writeCollectionBegin(elemType, size);
0171 }
0172
0173 /**
0174 * Write a map header. If the map is empty, omit the key and value type
0175 * headers, as we don't need any additional information to skip it.
0176 */
0177 template <class Transport_>
0178 uint32_t TCompactProtocolT<Transport_>::writeMapBegin(const TType keyType,
0179 const TType valType,
0180 const uint32_t size) {
0181 uint32_t wsize = 0;
0182
0183 if (size == 0) {
0184 wsize += writeByte(0);
0185 } else {
0186 wsize += writeVarint32(size);
0187 wsize += writeByte(getCompactType(keyType) << 4 | getCompactType(valType));
0188 }
0189 return wsize;
0190 }
0191
0192 /**
0193 * Write a boolean value. Potentially, this could be a boolean field, in
0194 * which case the field header info isn't written yet. If so, decide what the
0195 * right type header is for the value and then write the field header.
0196 * Otherwise, write a single byte.
0197 */
0198 template <class Transport_>
0199 uint32_t TCompactProtocolT<Transport_>::writeBool(const bool value) {
0200 uint32_t wsize = 0;
0201
0202 if (booleanField_.name != nullptr) {
0203 // we haven't written the field header yet
0204 wsize
0205 += writeFieldBeginInternal(booleanField_.name,
0206 booleanField_.fieldType,
0207 booleanField_.fieldId,
0208 static_cast<int8_t>(value
0209 ? detail::compact::CT_BOOLEAN_TRUE
0210 : detail::compact::CT_BOOLEAN_FALSE));
0211 booleanField_.name = nullptr;
0212 } else {
0213 // we're not part of a field, so just write the value
0214 wsize
0215 += writeByte(static_cast<int8_t>(value
0216 ? detail::compact::CT_BOOLEAN_TRUE
0217 : detail::compact::CT_BOOLEAN_FALSE));
0218 }
0219 return wsize;
0220 }
0221
0222 template <class Transport_>
0223 uint32_t TCompactProtocolT<Transport_>::writeByte(const int8_t byte) {
0224 trans_->write((uint8_t*)&byte, 1);
0225 return 1;
0226 }
0227
0228 /**
0229 * Write an i16 as a zigzag varint.
0230 */
0231 template <class Transport_>
0232 uint32_t TCompactProtocolT<Transport_>::writeI16(const int16_t i16) {
0233 return writeVarint32(i32ToZigzag(i16));
0234 }
0235
0236 /**
0237 * Write an i32 as a zigzag varint.
0238 */
0239 template <class Transport_>
0240 uint32_t TCompactProtocolT<Transport_>::writeI32(const int32_t i32) {
0241 return writeVarint32(i32ToZigzag(i32));
0242 }
0243
0244 /**
0245 * Write an i64 as a zigzag varint.
0246 */
0247 template <class Transport_>
0248 uint32_t TCompactProtocolT<Transport_>::writeI64(const int64_t i64) {
0249 return writeVarint64(i64ToZigzag(i64));
0250 }
0251
0252 /**
0253 * Write a double to the wire as 8 bytes.
0254 */
0255 template <class Transport_>
0256 uint32_t TCompactProtocolT<Transport_>::writeDouble(const double dub) {
0257 static_assert(sizeof(double) == sizeof(uint64_t), "sizeof(double) == sizeof(uint64_t)");
0258 static_assert(std::numeric_limits<double>::is_iec559, "std::numeric_limits<double>::is_iec559");
0259
0260 auto bits = bitwise_cast<uint64_t>(dub);
0261 bits = THRIFT_htolell(bits);
0262 trans_->write((uint8_t*)&bits, 8);
0263 return 8;
0264 }
0265
0266 /**
0267 * Write a string to the wire with a varint size preceding.
0268 */
0269 template <class Transport_>
0270 uint32_t TCompactProtocolT<Transport_>::writeString(const std::string& str) {
0271 return writeBinary(str);
0272 }
0273
0274 template <class Transport_>
0275 uint32_t TCompactProtocolT<Transport_>::writeBinary(const std::string& str) {
0276 if(str.size() > (std::numeric_limits<uint32_t>::max)())
0277 throw TProtocolException(TProtocolException::SIZE_LIMIT);
0278 auto ssize = static_cast<uint32_t>(str.size());
0279 uint32_t wsize = writeVarint32(ssize) ;
0280 // checking ssize + wsize > uint_max, but we don't want to overflow while checking for overflows.
0281 // transforming the check to ssize > uint_max - wsize
0282 if(ssize > (std::numeric_limits<uint32_t>::max)() - wsize)
0283 throw TProtocolException(TProtocolException::SIZE_LIMIT);
0284 wsize += ssize;
0285 trans_->write((uint8_t*)str.data(), ssize);
0286 return wsize;
0287 }
0288
0289 //
0290 // Internal Writing methods
0291 //
0292
0293 /**
0294 * The workhorse of writeFieldBegin. It has the option of doing a
0295 * 'type override' of the type header. This is used specifically in the
0296 * boolean field case.
0297 */
0298 template <class Transport_>
0299 int32_t TCompactProtocolT<Transport_>::writeFieldBeginInternal(
0300 const char* name,
0301 const TType fieldType,
0302 const int16_t fieldId,
0303 int8_t typeOverride) {
0304 (void) name;
0305 uint32_t wsize = 0;
0306
0307 // if there's a type override, use that.
0308 int8_t typeToWrite = (typeOverride == -1 ? getCompactType(fieldType) : typeOverride);
0309
0310 // check if we can use delta encoding for the field id
0311 if (fieldId > lastFieldId_ && fieldId - lastFieldId_ <= 15) {
0312 // write them together
0313 wsize += writeByte(static_cast<int8_t>((fieldId - lastFieldId_)
0314 << 4 | typeToWrite));
0315 } else {
0316 // write them separate
0317 wsize += writeByte(typeToWrite);
0318 wsize += writeI16(fieldId);
0319 }
0320
0321 lastFieldId_ = fieldId;
0322 return wsize;
0323 }
0324
0325 /**
0326 * Abstract method for writing the start of lists and sets. List and sets on
0327 * the wire differ only by the type indicator.
0328 */
0329 template <class Transport_>
0330 uint32_t TCompactProtocolT<Transport_>::writeCollectionBegin(const TType elemType,
0331 int32_t size) {
0332 uint32_t wsize = 0;
0333 if (size <= 14) {
0334 wsize += writeByte(static_cast<int8_t>(size
0335 << 4 | getCompactType(elemType)));
0336 } else {
0337 wsize += writeByte(0xf0 | getCompactType(elemType));
0338 wsize += writeVarint32(size);
0339 }
0340 return wsize;
0341 }
0342
0343 /**
0344 * Write an i32 as a varint. Results in 1-5 bytes on the wire.
0345 */
0346 template <class Transport_>
0347 uint32_t TCompactProtocolT<Transport_>::writeVarint32(uint32_t n) {
0348 uint8_t buf[5];
0349 uint32_t wsize = 0;
0350
0351 while (true) {
0352 if ((n & ~0x7F) == 0) {
0353 buf[wsize++] = (int8_t)n;
0354 break;
0355 } else {
0356 buf[wsize++] = (int8_t)((n & 0x7F) | 0x80);
0357 n >>= 7;
0358 }
0359 }
0360 trans_->write(buf, wsize);
0361 return wsize;
0362 }
0363
0364 /**
0365 * Write an i64 as a varint. Results in 1-10 bytes on the wire.
0366 */
0367 template <class Transport_>
0368 uint32_t TCompactProtocolT<Transport_>::writeVarint64(uint64_t n) {
0369 uint8_t buf[10];
0370 uint32_t wsize = 0;
0371
0372 while (true) {
0373 if ((n & ~0x7FL) == 0) {
0374 buf[wsize++] = (int8_t)n;
0375 break;
0376 } else {
0377 buf[wsize++] = (int8_t)((n & 0x7F) | 0x80);
0378 n >>= 7;
0379 }
0380 }
0381 trans_->write(buf, wsize);
0382 return wsize;
0383 }
0384
0385 /**
0386 * Convert l into a zigzag long. This allows negative numbers to be
0387 * represented compactly as a varint.
0388 */
0389 template <class Transport_>
0390 uint64_t TCompactProtocolT<Transport_>::i64ToZigzag(const int64_t l) {
0391 return (static_cast<uint64_t>(l) << 1) ^ (l >> 63);
0392 }
0393
0394 /**
0395 * Convert n into a zigzag int. This allows negative numbers to be
0396 * represented compactly as a varint.
0397 */
0398 template <class Transport_>
0399 uint32_t TCompactProtocolT<Transport_>::i32ToZigzag(const int32_t n) {
0400 return (static_cast<uint32_t>(n) << 1) ^ (n >> 31);
0401 }
0402
0403 /**
0404 * Given a TType value, find the appropriate detail::compact::Types value
0405 */
0406 template <class Transport_>
0407 int8_t TCompactProtocolT<Transport_>::getCompactType(const TType ttype) {
0408 return detail::compact::TTypeToCType[ttype];
0409 }
0410
0411 //
0412 // Reading Methods
0413 //
0414
0415 /**
0416 * Read a message header.
0417 */
0418 template <class Transport_>
0419 uint32_t TCompactProtocolT<Transport_>::readMessageBegin(
0420 std::string& name,
0421 TMessageType& messageType,
0422 int32_t& seqid) {
0423 uint32_t rsize = 0;
0424 int8_t protocolId;
0425 int8_t versionAndType;
0426 int8_t version;
0427
0428 rsize += readByte(protocolId);
0429 if (protocolId != PROTOCOL_ID) {
0430 throw TProtocolException(TProtocolException::BAD_VERSION, "Bad protocol identifier");
0431 }
0432
0433 rsize += readByte(versionAndType);
0434 version = (int8_t)(versionAndType & VERSION_MASK);
0435 if (version != VERSION_N) {
0436 throw TProtocolException(TProtocolException::BAD_VERSION, "Bad protocol version");
0437 }
0438
0439 messageType = (TMessageType)((versionAndType >> TYPE_SHIFT_AMOUNT) & TYPE_BITS);
0440 rsize += readVarint32(seqid);
0441 rsize += readString(name);
0442
0443 return rsize;
0444 }
0445
0446 /**
0447 * Read a struct begin. There's nothing on the wire for this, but it is our
0448 * opportunity to push a new struct begin marker on the field stack.
0449 */
0450 template <class Transport_>
0451 uint32_t TCompactProtocolT<Transport_>::readStructBegin(std::string& name) {
0452 name = "";
0453 lastField_.push(lastFieldId_);
0454 lastFieldId_ = 0;
0455 return 0;
0456 }
0457
0458 /**
0459 * Doesn't actually consume any wire data, just removes the last field for
0460 * this struct from the field stack.
0461 */
0462 template <class Transport_>
0463 uint32_t TCompactProtocolT<Transport_>::readStructEnd() {
0464 lastFieldId_ = lastField_.top();
0465 lastField_.pop();
0466 return 0;
0467 }
0468
0469 /**
0470 * Read a field header off the wire.
0471 */
0472 template <class Transport_>
0473 uint32_t TCompactProtocolT<Transport_>::readFieldBegin(std::string& name,
0474 TType& fieldType,
0475 int16_t& fieldId) {
0476 (void) name;
0477 uint32_t rsize = 0;
0478 int8_t byte;
0479 int8_t type;
0480
0481 rsize += readByte(byte);
0482 type = (byte & 0x0f);
0483
0484 // if it's a stop, then we can return immediately, as the struct is over.
0485 if (type == T_STOP) {
0486 fieldType = T_STOP;
0487 fieldId = 0;
0488 return rsize;
0489 }
0490
0491 // mask off the 4 MSB of the type header. it could contain a field id delta.
0492 auto modifier = (int16_t)(((uint8_t)byte & 0xf0) >> 4);
0493 if (modifier == 0) {
0494 // not a delta, look ahead for the zigzag varint field id.
0495 rsize += readI16(fieldId);
0496 } else {
0497 fieldId = (int16_t)(lastFieldId_ + modifier);
0498 }
0499 fieldType = getTType(type);
0500
0501 // if this happens to be a boolean field, the value is encoded in the type
0502 if (type == detail::compact::CT_BOOLEAN_TRUE ||
0503 type == detail::compact::CT_BOOLEAN_FALSE) {
0504 // save the boolean value in a special instance variable.
0505 boolValue_.hasBoolValue = true;
0506 boolValue_.boolValue =
0507 (type == detail::compact::CT_BOOLEAN_TRUE ? true : false);
0508 }
0509
0510 // push the new field onto the field stack so we can keep the deltas going.
0511 lastFieldId_ = fieldId;
0512 return rsize;
0513 }
0514
0515 /**
0516 * Read a map header off the wire. If the size is zero, skip reading the key
0517 * and value type. This means that 0-length maps will yield TMaps without the
0518 * "correct" types.
0519 */
0520 template <class Transport_>
0521 uint32_t TCompactProtocolT<Transport_>::readMapBegin(TType& keyType,
0522 TType& valType,
0523 uint32_t& size) {
0524 uint32_t rsize = 0;
0525 int8_t kvType = 0;
0526 int32_t msize = 0;
0527
0528 rsize += readVarint32(msize);
0529 if (msize != 0)
0530 rsize += readByte(kvType);
0531
0532 if (msize < 0) {
0533 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
0534 } else if (container_limit_ && msize > container_limit_) {
0535 throw TProtocolException(TProtocolException::SIZE_LIMIT);
0536 }
0537
0538 keyType = getTType((int8_t)((uint8_t)kvType >> 4));
0539 valType = getTType((int8_t)((uint8_t)kvType & 0xf));
0540 size = (uint32_t)msize;
0541
0542 TMap map(keyType, valType, size);
0543 checkReadBytesAvailable(map);
0544
0545 return rsize;
0546 }
0547
0548 /**
0549 * Read a list header off the wire. If the list size is 0-14, the size will
0550 * be packed into the element type header. If it's a longer list, the 4 MSB
0551 * of the element type header will be 0xF, and a varint will follow with the
0552 * true size.
0553 */
0554 template <class Transport_>
0555 uint32_t TCompactProtocolT<Transport_>::readListBegin(TType& elemType,
0556 uint32_t& size) {
0557 int8_t size_and_type;
0558 uint32_t rsize = 0;
0559 int32_t lsize;
0560
0561 rsize += readByte(size_and_type);
0562
0563 lsize = ((uint8_t)size_and_type >> 4) & 0x0f;
0564 if (lsize == 15) {
0565 rsize += readVarint32(lsize);
0566 }
0567
0568 if (lsize < 0) {
0569 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
0570 } else if (container_limit_ && lsize > container_limit_) {
0571 throw TProtocolException(TProtocolException::SIZE_LIMIT);
0572 }
0573
0574 elemType = getTType((int8_t)(size_and_type & 0x0f));
0575 size = (uint32_t)lsize;
0576
0577 TList list(elemType, size);
0578 checkReadBytesAvailable(list);
0579
0580 return rsize;
0581 }
0582
0583 /**
0584 * Read a set header off the wire. If the set size is 0-14, the size will
0585 * be packed into the element type header. If it's a longer set, the 4 MSB
0586 * of the element type header will be 0xF, and a varint will follow with the
0587 * true size.
0588 */
0589 template <class Transport_>
0590 uint32_t TCompactProtocolT<Transport_>::readSetBegin(TType& elemType,
0591 uint32_t& size) {
0592 return readListBegin(elemType, size);
0593 }
0594
0595 /**
0596 * Read a boolean off the wire. If this is a boolean field, the value should
0597 * already have been read during readFieldBegin, so we'll just consume the
0598 * pre-stored value. Otherwise, read a byte.
0599 */
0600 template <class Transport_>
0601 uint32_t TCompactProtocolT<Transport_>::readBool(bool& value) {
0602 if (boolValue_.hasBoolValue == true) {
0603 value = boolValue_.boolValue;
0604 boolValue_.hasBoolValue = false;
0605 return 0;
0606 } else {
0607 int8_t val;
0608 readByte(val);
0609 value = (val == detail::compact::CT_BOOLEAN_TRUE);
0610 return 1;
0611 }
0612 }
0613
0614 /**
0615 * Read a single byte off the wire. Nothing interesting here.
0616 */
0617 template <class Transport_>
0618 uint32_t TCompactProtocolT<Transport_>::readByte(int8_t& byte) {
0619 uint8_t b[1];
0620 trans_->readAll(b, 1);
0621 byte = *(int8_t*)b;
0622 return 1;
0623 }
0624
0625 /**
0626 * Read an i16 from the wire as a zigzag varint.
0627 */
0628 template <class Transport_>
0629 uint32_t TCompactProtocolT<Transport_>::readI16(int16_t& i16) {
0630 int32_t value;
0631 uint32_t rsize = readVarint32(value);
0632 i16 = (int16_t)zigzagToI32(value);
0633 return rsize;
0634 }
0635
0636 /**
0637 * Read an i32 from the wire as a zigzag varint.
0638 */
0639 template <class Transport_>
0640 uint32_t TCompactProtocolT<Transport_>::readI32(int32_t& i32) {
0641 int32_t value;
0642 uint32_t rsize = readVarint32(value);
0643 i32 = zigzagToI32(value);
0644 return rsize;
0645 }
0646
0647 /**
0648 * Read an i64 from the wire as a zigzag varint.
0649 */
0650 template <class Transport_>
0651 uint32_t TCompactProtocolT<Transport_>::readI64(int64_t& i64) {
0652 int64_t value;
0653 uint32_t rsize = readVarint64(value);
0654 i64 = zigzagToI64(value);
0655 return rsize;
0656 }
0657
0658 /**
0659 * No magic here - just read a double off the wire.
0660 */
0661 template <class Transport_>
0662 uint32_t TCompactProtocolT<Transport_>::readDouble(double& dub) {
0663 static_assert(sizeof(double) == sizeof(uint64_t), "sizeof(double) == sizeof(uint64_t)");
0664 static_assert(std::numeric_limits<double>::is_iec559, "std::numeric_limits<double>::is_iec559");
0665
0666 union {
0667 uint64_t bits;
0668 uint8_t b[8];
0669 } u;
0670 trans_->readAll(u.b, 8);
0671 u.bits = THRIFT_letohll(u.bits);
0672 dub = bitwise_cast<double>(u.bits);
0673 return 8;
0674 }
0675
0676 template <class Transport_>
0677 uint32_t TCompactProtocolT<Transport_>::readString(std::string& str) {
0678 return readBinary(str);
0679 }
0680
0681 /**
0682 * Read a byte[] from the wire.
0683 */
0684 template <class Transport_>
0685 uint32_t TCompactProtocolT<Transport_>::readBinary(std::string& str) {
0686 int32_t rsize = 0;
0687 int32_t size;
0688
0689 rsize += readVarint32(size);
0690 // Catch empty string case
0691 if (size == 0) {
0692 str = "";
0693 return rsize;
0694 }
0695
0696 // Catch error cases
0697 if (size < 0) {
0698 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
0699 }
0700 if (string_limit_ > 0 && size > string_limit_) {
0701 throw TProtocolException(TProtocolException::SIZE_LIMIT);
0702 }
0703
0704 // Use the heap here to prevent stack overflow for v. large strings
0705 if (size > string_buf_size_ || string_buf_ == nullptr) {
0706 void* new_string_buf = std::realloc(string_buf_, (uint32_t)size);
0707 if (new_string_buf == nullptr) {
0708 throw std::bad_alloc();
0709 }
0710 string_buf_ = (uint8_t*)new_string_buf;
0711 string_buf_size_ = size;
0712 }
0713 trans_->readAll(string_buf_, size);
0714 str.assign((char*)string_buf_, size);
0715
0716 trans_->checkReadBytesAvailable(rsize + (uint32_t)size);
0717
0718 return rsize + (uint32_t)size;
0719 }
0720
0721 /**
0722 * Read an i32 from the wire as a varint. The MSB of each byte is set
0723 * if there is another byte to follow. This can read up to 5 bytes.
0724 */
0725 template <class Transport_>
0726 uint32_t TCompactProtocolT<Transport_>::readVarint32(int32_t& i32) {
0727 int64_t val;
0728 uint32_t rsize = readVarint64(val);
0729 i32 = (int32_t)val;
0730 return rsize;
0731 }
0732
0733 /**
0734 * Read an i64 from the wire as a proper varint. The MSB of each byte is set
0735 * if there is another byte to follow. This can read up to 10 bytes.
0736 */
0737 template <class Transport_>
0738 uint32_t TCompactProtocolT<Transport_>::readVarint64(int64_t& i64) {
0739 uint32_t rsize = 0;
0740 uint64_t val = 0;
0741 int shift = 0;
0742 uint8_t buf[10]; // 64 bits / (7 bits/byte) = 10 bytes.
0743 uint32_t buf_size = sizeof(buf);
0744 const uint8_t* borrowed = trans_->borrow(buf, &buf_size);
0745
0746 // Fast path.
0747 if (borrowed != nullptr) {
0748 while (true) {
0749 uint8_t byte = borrowed[rsize];
0750 rsize++;
0751 val |= (uint64_t)(byte & 0x7f) << shift;
0752 shift += 7;
0753 if (!(byte & 0x80)) {
0754 i64 = val;
0755 trans_->consume(rsize);
0756 return rsize;
0757 }
0758 // Have to check for invalid data so we don't crash.
0759 if (UNLIKELY(rsize == sizeof(buf))) {
0760 throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
0761 }
0762 }
0763 }
0764
0765 // Slow path.
0766 else {
0767 while (true) {
0768 uint8_t byte;
0769 rsize += trans_->readAll(&byte, 1);
0770 val |= (uint64_t)(byte & 0x7f) << shift;
0771 shift += 7;
0772 if (!(byte & 0x80)) {
0773 i64 = val;
0774 return rsize;
0775 }
0776 // Might as well check for invalid data on the slow path too.
0777 if (UNLIKELY(rsize >= sizeof(buf))) {
0778 throw TProtocolException(TProtocolException::INVALID_DATA, "Variable-length int over 10 bytes.");
0779 }
0780 }
0781 }
0782 }
0783
0784 /**
0785 * Convert from zigzag int to int.
0786 */
0787 template <class Transport_>
0788 int32_t TCompactProtocolT<Transport_>::zigzagToI32(uint32_t n) {
0789 return (n >> 1) ^ static_cast<uint32_t>(-static_cast<int32_t>(n & 1));
0790 }
0791
0792 /**
0793 * Convert from zigzag long to long.
0794 */
0795 template <class Transport_>
0796 int64_t TCompactProtocolT<Transport_>::zigzagToI64(uint64_t n) {
0797 return (n >> 1) ^ static_cast<uint64_t>(-static_cast<int64_t>(n & 1));
0798 }
0799
0800 template <class Transport_>
0801 TType TCompactProtocolT<Transport_>::getTType(int8_t type) {
0802 switch (type) {
0803 case T_STOP:
0804 return T_STOP;
0805 case detail::compact::CT_BOOLEAN_FALSE:
0806 case detail::compact::CT_BOOLEAN_TRUE:
0807 return T_BOOL;
0808 case detail::compact::CT_BYTE:
0809 return T_BYTE;
0810 case detail::compact::CT_I16:
0811 return T_I16;
0812 case detail::compact::CT_I32:
0813 return T_I32;
0814 case detail::compact::CT_I64:
0815 return T_I64;
0816 case detail::compact::CT_DOUBLE:
0817 return T_DOUBLE;
0818 case detail::compact::CT_BINARY:
0819 return T_STRING;
0820 case detail::compact::CT_LIST:
0821 return T_LIST;
0822 case detail::compact::CT_SET:
0823 return T_SET;
0824 case detail::compact::CT_MAP:
0825 return T_MAP;
0826 case detail::compact::CT_STRUCT:
0827 return T_STRUCT;
0828 default:
0829 throw TException(std::string("don't know what type: ") + (char)type);
0830 }
0831 }
0832
0833 // Return the minimum number of bytes a type will consume on the wire
0834 template <class Transport_>
0835 int TCompactProtocolT<Transport_>::getMinSerializedSize(TType type)
0836 {
0837 switch (type)
0838 {
0839 case T_STOP: return 0;
0840 case T_VOID: return 0;
0841 case T_BOOL: return sizeof(int8_t);
0842 case T_DOUBLE: return 8; // uses fixedLongToBytes() which always writes 8 bytes
0843 case T_BYTE: return sizeof(int8_t);
0844 case T_I16: return sizeof(int8_t); // zigzag
0845 case T_I32: return sizeof(int8_t); // zigzag
0846 case T_I64: return sizeof(int8_t); // zigzag
0847 case T_STRING: return sizeof(int8_t); // string length
0848 case T_STRUCT: return 0; // empty struct
0849 case T_MAP: return sizeof(int8_t); // element count
0850 case T_SET: return sizeof(int8_t); // element count
0851 case T_LIST: return sizeof(int8_t); // element count
0852 default: throw TProtocolException(TProtocolException::UNKNOWN, "unrecognized type code");
0853 }
0854 }
0855
0856
0857 }}} // apache::thrift::protocol
0858
0859 #endif // _THRIFT_PROTOCOL_TCOMPACTPROTOCOL_TCC_