blob: 5116e86523687ef506b6a42e171cbaa1a8bf17a0 [file] [log] [blame]
Mark Slee9f0c6512007-02-28 23:58:26 +00001// Copyright (c) 2006- Facebook
2// Distributed under the Thrift Software License
3//
4// See accompanying file LICENSE or visit the Thrift site at:
5// http://developers.facebook.com/thrift/
6
Marc Slemkod42a2c22006-08-10 03:30:18 +00007#include "TBinaryProtocol.h"
8
Mark Slee4f261c52007-04-13 00:33:24 +00009#include <boost/static_assert.hpp>
10
Mark Slee8d7e1f62006-06-07 06:48:56 +000011using std::string;
Mark Sleee8540632006-05-30 09:24:40 +000012
Mark Slee4f261c52007-04-13 00:33:24 +000013// Use this to get around strict aliasing rules.
14// For example, uint64_t i = bitwise_cast<uint64_t>(returns_double());
15// The most obvious implementation is to just cast a pointer,
16// but that doesn't work.
17// For a pretty in-depth explanation of the problem, see
18// http://www.cellperformance.com/mike_acton/2006/06/ (...)
19// understanding_strict_aliasing.html
20template <typename To, typename From>
21static inline To bitwise_cast(From from) {
22 BOOST_STATIC_ASSERT(sizeof(From) == sizeof(To));
23
24 // BAD!!! These are all broken with -O2.
25 //return *reinterpret_cast<To*>(&from); // BAD!!!
26 //return *static_cast<To*>(static_cast<void*>(&from)); // BAD!!!
27 //return *(To*)(void*)&from; // BAD!!!
28
29 // Super clean and paritally blessed by section 3.9 of the standard.
30 //unsigned char c[sizeof(from)];
31 //memcpy(c, &from, sizeof(from));
32 //To to;
33 //memcpy(&to, c, sizeof(c));
34 //return to;
35
36 // Slightly more questionable.
37 // Same code emitted by GCC.
38 //To to;
39 //memcpy(&to, &from, sizeof(from));
40 //return to;
41
42 // Technically undefined, but almost universally supported,
43 // and the most efficient implementation.
44 union {
45 From f;
46 To t;
47 } u;
48 u.f = from;
49 return u.t;
50}
51
52
Marc Slemko6f038a72006-08-03 18:58:09 +000053namespace facebook { namespace thrift { namespace protocol {
54
Mark Slee82a6c0f2007-04-04 21:08:21 +000055uint32_t TBinaryProtocol::writeMessageBegin(const std::string& name,
56 const TMessageType messageType,
57 const int32_t seqid) {
Marc Slemko16698852006-08-04 03:16:10 +000058 return
Mark Slee4af6ed72006-10-25 19:02:49 +000059 writeString(name) +
60 writeByte((int8_t)messageType) +
61 writeI32(seqid);
Marc Slemko16698852006-08-04 03:16:10 +000062}
63
Mark Slee4af6ed72006-10-25 19:02:49 +000064uint32_t TBinaryProtocol::writeMessageEnd() {
Marc Slemko16698852006-08-04 03:16:10 +000065 return 0;
66}
67
Mark Slee4af6ed72006-10-25 19:02:49 +000068uint32_t TBinaryProtocol::writeStructBegin(const string& name) {
Mark Slee8d7e1f62006-06-07 06:48:56 +000069 return 0;
Mark Sleee8540632006-05-30 09:24:40 +000070}
71
Mark Slee4af6ed72006-10-25 19:02:49 +000072uint32_t TBinaryProtocol::writeStructEnd() {
Mark Slee8d7e1f62006-06-07 06:48:56 +000073 return 0;
Mark Sleee8540632006-05-30 09:24:40 +000074}
75
Mark Slee4af6ed72006-10-25 19:02:49 +000076uint32_t TBinaryProtocol::writeFieldBegin(const string& name,
Mark Slee8d7e1f62006-06-07 06:48:56 +000077 const TType fieldType,
Mark Slee4af6ed72006-10-25 19:02:49 +000078 const int16_t fieldId) {
Mark Slee8d7e1f62006-06-07 06:48:56 +000079 return
Mark Slee4af6ed72006-10-25 19:02:49 +000080 writeByte((int8_t)fieldType) +
81 writeI16(fieldId);
Mark Slee8d7e1f62006-06-07 06:48:56 +000082}
83
Mark Slee4af6ed72006-10-25 19:02:49 +000084uint32_t TBinaryProtocol::writeFieldEnd() {
Mark Slee8d7e1f62006-06-07 06:48:56 +000085 return 0;
86}
87
Mark Slee4af6ed72006-10-25 19:02:49 +000088uint32_t TBinaryProtocol::writeFieldStop() {
Mark Slee8d7e1f62006-06-07 06:48:56 +000089 return
Mark Slee4af6ed72006-10-25 19:02:49 +000090 writeByte((int8_t)T_STOP);
Mark Slee8d7e1f62006-06-07 06:48:56 +000091}
92
Mark Slee4af6ed72006-10-25 19:02:49 +000093uint32_t TBinaryProtocol::writeMapBegin(const TType keyType,
Mark Slee8d7e1f62006-06-07 06:48:56 +000094 const TType valType,
Mark Slee4af6ed72006-10-25 19:02:49 +000095 const uint32_t size) {
Mark Slee8d7e1f62006-06-07 06:48:56 +000096 return
Mark Slee4af6ed72006-10-25 19:02:49 +000097 writeByte((int8_t)keyType) +
98 writeByte((int8_t)valType) +
99 writeI32((int32_t)size);
Mark Slee8d7e1f62006-06-07 06:48:56 +0000100}
101
Mark Slee4af6ed72006-10-25 19:02:49 +0000102uint32_t TBinaryProtocol::writeMapEnd() {
Mark Slee8d7e1f62006-06-07 06:48:56 +0000103 return 0;
104}
105
Mark Slee4af6ed72006-10-25 19:02:49 +0000106uint32_t TBinaryProtocol::writeListBegin(const TType elemType,
107 const uint32_t size) {
Mark Slee8d7e1f62006-06-07 06:48:56 +0000108 return
Mark Slee4af6ed72006-10-25 19:02:49 +0000109 writeByte((int8_t) elemType) +
110 writeI32((int32_t)size);
Mark Slee8d7e1f62006-06-07 06:48:56 +0000111}
112
Mark Slee4af6ed72006-10-25 19:02:49 +0000113uint32_t TBinaryProtocol::writeListEnd() {
Mark Slee8d7e1f62006-06-07 06:48:56 +0000114 return 0;
115}
116
Mark Slee4af6ed72006-10-25 19:02:49 +0000117uint32_t TBinaryProtocol::writeSetBegin(const TType elemType,
118 const uint32_t size) {
Mark Slee8d7e1f62006-06-07 06:48:56 +0000119 return
Mark Slee4af6ed72006-10-25 19:02:49 +0000120 writeByte((int8_t)elemType) +
121 writeI32((int32_t)size);
Mark Slee8d7e1f62006-06-07 06:48:56 +0000122}
123
Mark Slee4af6ed72006-10-25 19:02:49 +0000124uint32_t TBinaryProtocol::writeSetEnd() {
Mark Slee8d7e1f62006-06-07 06:48:56 +0000125 return 0;
126}
127
Mark Slee4af6ed72006-10-25 19:02:49 +0000128uint32_t TBinaryProtocol::writeBool(const bool value) {
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000129 uint8_t tmp = value ? 1 : 0;
Aditya Agarwal9abb0d62007-01-24 22:53:54 +0000130 trans_->write(&tmp, 1);
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000131 return 1;
132}
133
Mark Slee4af6ed72006-10-25 19:02:49 +0000134uint32_t TBinaryProtocol::writeByte(const int8_t byte) {
Aditya Agarwal9abb0d62007-01-24 22:53:54 +0000135 trans_->write((uint8_t*)&byte, 1);
Mark Slee8d7e1f62006-06-07 06:48:56 +0000136 return 1;
137}
138
Mark Slee4af6ed72006-10-25 19:02:49 +0000139uint32_t TBinaryProtocol::writeI16(const int16_t i16) {
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000140 int16_t net = (int16_t)htons(i16);
Aditya Agarwal9abb0d62007-01-24 22:53:54 +0000141 trans_->write((uint8_t*)&net, 2);
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000142 return 2;
Mark Slee8d7e1f62006-06-07 06:48:56 +0000143}
144
Mark Slee4af6ed72006-10-25 19:02:49 +0000145uint32_t TBinaryProtocol::writeI32(const int32_t i32) {
Marc Slemkoe6889de2006-08-12 00:32:53 +0000146 int32_t net = (int32_t)htonl(i32);
Aditya Agarwal9abb0d62007-01-24 22:53:54 +0000147 trans_->write((uint8_t*)&net, 4);
Marc Slemkoe6889de2006-08-12 00:32:53 +0000148 return 4;
149}
150
Mark Slee4af6ed72006-10-25 19:02:49 +0000151uint32_t TBinaryProtocol::writeI64(const int64_t i64) {
Mark Slee8d7e1f62006-06-07 06:48:56 +0000152 int64_t net = (int64_t)htonll(i64);
Aditya Agarwal9abb0d62007-01-24 22:53:54 +0000153 trans_->write((uint8_t*)&net, 8);
Mark Slee8d7e1f62006-06-07 06:48:56 +0000154 return 8;
155}
Mark Sleec98d0502006-09-06 02:42:25 +0000156
Mark Slee4af6ed72006-10-25 19:02:49 +0000157uint32_t TBinaryProtocol::writeDouble(const double dub) {
Mark Slee4f261c52007-04-13 00:33:24 +0000158 BOOST_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t));
159 BOOST_STATIC_ASSERT(std::numeric_limits<double>::is_iec559);
160
161 uint64_t bits = bitwise_cast<uint64_t>(dub);
162 bits = htonll(bits);
163 trans_->write((uint8_t*)&bits, 8);
Mark Sleec98d0502006-09-06 02:42:25 +0000164 return 8;
165}
Mark Slee8d7e1f62006-06-07 06:48:56 +0000166
Mark Sleec98d0502006-09-06 02:42:25 +0000167
Mark Slee4af6ed72006-10-25 19:02:49 +0000168uint32_t TBinaryProtocol::writeString(const string& str) {
Mark Sleef9831082007-02-20 20:59:21 +0000169 uint32_t size = str.size();
170 uint32_t result = writeI32((int32_t)size);
171 if (size > 0) {
172 trans_->write((uint8_t*)str.data(), size);
173 }
174 return result + size;
Mark Slee8d7e1f62006-06-07 06:48:56 +0000175}
176
177/**
178 * Reading functions
179 */
180
Mark Slee4af6ed72006-10-25 19:02:49 +0000181uint32_t TBinaryProtocol::readMessageBegin(std::string& name,
Marc Slemkoe6889de2006-08-12 00:32:53 +0000182 TMessageType& messageType,
Mark Slee4af6ed72006-10-25 19:02:49 +0000183 int32_t& seqid) {
Marc Slemko16698852006-08-04 03:16:10 +0000184
185 uint32_t result = 0;
Mark Sleecfc01932006-09-01 22:18:16 +0000186 int8_t type;
Mark Slee4af6ed72006-10-25 19:02:49 +0000187 result+= readString(name);
188 result+= readByte(type);
Marc Slemko16698852006-08-04 03:16:10 +0000189 messageType = (TMessageType)type;
Mark Slee4af6ed72006-10-25 19:02:49 +0000190 result+= readI32(seqid);
Marc Slemko16698852006-08-04 03:16:10 +0000191 return result;
192}
193
Mark Slee4af6ed72006-10-25 19:02:49 +0000194uint32_t TBinaryProtocol::readMessageEnd() {
Marc Slemko16698852006-08-04 03:16:10 +0000195 return 0;
196}
197
Mark Slee4af6ed72006-10-25 19:02:49 +0000198uint32_t TBinaryProtocol::readStructBegin(string& name) {
Mark Slee8d7e1f62006-06-07 06:48:56 +0000199 name = "";
200 return 0;
201}
202
Mark Slee4af6ed72006-10-25 19:02:49 +0000203uint32_t TBinaryProtocol::readStructEnd() {
Mark Slee8d7e1f62006-06-07 06:48:56 +0000204 return 0;
205}
206
Mark Slee4af6ed72006-10-25 19:02:49 +0000207uint32_t TBinaryProtocol::readFieldBegin(string& name,
Mark Slee8d7e1f62006-06-07 06:48:56 +0000208 TType& fieldType,
Mark Slee4af6ed72006-10-25 19:02:49 +0000209 int16_t& fieldId) {
Mark Slee8d7e1f62006-06-07 06:48:56 +0000210 uint32_t result = 0;
Mark Sleecfc01932006-09-01 22:18:16 +0000211 int8_t type;
Mark Slee4af6ed72006-10-25 19:02:49 +0000212 result += readByte(type);
Mark Slee8d7e1f62006-06-07 06:48:56 +0000213 fieldType = (TType)type;
214 if (fieldType == T_STOP) {
215 fieldId = 0;
216 return result;
217 }
Mark Slee4af6ed72006-10-25 19:02:49 +0000218 result += readI16(fieldId);
Mark Slee8d7e1f62006-06-07 06:48:56 +0000219 return result;
220}
Mark Sleee8540632006-05-30 09:24:40 +0000221
Mark Slee4af6ed72006-10-25 19:02:49 +0000222uint32_t TBinaryProtocol::readFieldEnd() {
Mark Slee8d7e1f62006-06-07 06:48:56 +0000223 return 0;
Mark Sleee8540632006-05-30 09:24:40 +0000224}
Mark Slee8d7e1f62006-06-07 06:48:56 +0000225
Mark Slee4af6ed72006-10-25 19:02:49 +0000226uint32_t TBinaryProtocol::readMapBegin(TType& keyType,
Mark Slee8d7e1f62006-06-07 06:48:56 +0000227 TType& valType,
Mark Slee4af6ed72006-10-25 19:02:49 +0000228 uint32_t& size) {
Mark Sleecfc01932006-09-01 22:18:16 +0000229 int8_t k, v;
Mark Slee8d7e1f62006-06-07 06:48:56 +0000230 uint32_t result = 0;
Mark Sleecfc01932006-09-01 22:18:16 +0000231 int32_t sizei;
Mark Slee4af6ed72006-10-25 19:02:49 +0000232 result += readByte(k);
Mark Slee8d7e1f62006-06-07 06:48:56 +0000233 keyType = (TType)k;
Mark Slee4af6ed72006-10-25 19:02:49 +0000234 result += readByte(v);
Mark Slee8d7e1f62006-06-07 06:48:56 +0000235 valType = (TType)v;
Mark Slee4af6ed72006-10-25 19:02:49 +0000236 result += readI32(sizei);
Mark Sleef9831082007-02-20 20:59:21 +0000237 if (sizei < 0) {
238 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
239 } else if (container_limit_ && sizei > container_limit_) {
240 throw TProtocolException(TProtocolException::SIZE_LIMIT);
241 }
Mark Sleecfc01932006-09-01 22:18:16 +0000242 size = (uint32_t)sizei;
Mark Sleee8540632006-05-30 09:24:40 +0000243 return result;
244}
245
Mark Slee4af6ed72006-10-25 19:02:49 +0000246uint32_t TBinaryProtocol::readMapEnd() {
Mark Slee8d7e1f62006-06-07 06:48:56 +0000247 return 0;
248}
249
Mark Slee4af6ed72006-10-25 19:02:49 +0000250uint32_t TBinaryProtocol::readListBegin(TType& elemType,
251 uint32_t& size) {
Mark Sleecfc01932006-09-01 22:18:16 +0000252 int8_t e;
Mark Slee8d7e1f62006-06-07 06:48:56 +0000253 uint32_t result = 0;
Mark Sleecfc01932006-09-01 22:18:16 +0000254 int32_t sizei;
Mark Slee4af6ed72006-10-25 19:02:49 +0000255 result += readByte(e);
Mark Slee8d7e1f62006-06-07 06:48:56 +0000256 elemType = (TType)e;
Mark Slee4af6ed72006-10-25 19:02:49 +0000257 result += readI32(sizei);
Mark Sleef9831082007-02-20 20:59:21 +0000258 if (sizei < 0) {
259 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
260 } else if (container_limit_ && sizei > container_limit_) {
261 throw TProtocolException(TProtocolException::SIZE_LIMIT);
262 }
Mark Sleecfc01932006-09-01 22:18:16 +0000263 size = (uint32_t)sizei;
Mark Sleee8540632006-05-30 09:24:40 +0000264 return result;
265}
266
Mark Slee4af6ed72006-10-25 19:02:49 +0000267uint32_t TBinaryProtocol::readListEnd() {
Mark Slee8d7e1f62006-06-07 06:48:56 +0000268 return 0;
269}
270
Mark Slee4af6ed72006-10-25 19:02:49 +0000271uint32_t TBinaryProtocol::readSetBegin(TType& elemType,
272 uint32_t& size) {
Mark Sleecfc01932006-09-01 22:18:16 +0000273 int8_t e;
Mark Slee8d7e1f62006-06-07 06:48:56 +0000274 uint32_t result = 0;
Mark Sleecfc01932006-09-01 22:18:16 +0000275 int32_t sizei;
Mark Slee4af6ed72006-10-25 19:02:49 +0000276 result += readByte(e);
Mark Slee8d7e1f62006-06-07 06:48:56 +0000277 elemType = (TType)e;
Mark Slee4af6ed72006-10-25 19:02:49 +0000278 result += readI32(sizei);
Mark Sleef9831082007-02-20 20:59:21 +0000279 if (sizei < 0) {
280 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
281 } else if (container_limit_ && sizei > container_limit_) {
282 throw TProtocolException(TProtocolException::SIZE_LIMIT);
283 }
Mark Sleecfc01932006-09-01 22:18:16 +0000284 size = (uint32_t)sizei;
Mark Sleee8540632006-05-30 09:24:40 +0000285 return result;
286}
287
Mark Slee4af6ed72006-10-25 19:02:49 +0000288uint32_t TBinaryProtocol::readSetEnd() {
Mark Slee8d7e1f62006-06-07 06:48:56 +0000289 return 0;
Mark Sleee8540632006-05-30 09:24:40 +0000290}
291
Mark Slee4af6ed72006-10-25 19:02:49 +0000292uint32_t TBinaryProtocol::readBool(bool& value) {
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000293 uint8_t b[1];
Aditya Agarwal9abb0d62007-01-24 22:53:54 +0000294 trans_->readAll(b, 1);
Mark Sleecfc01932006-09-01 22:18:16 +0000295 value = *(int8_t*)b != 0;
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000296 return 1;
297}
298
Mark Slee4af6ed72006-10-25 19:02:49 +0000299uint32_t TBinaryProtocol::readByte(int8_t& byte) {
Mark Slee8d7e1f62006-06-07 06:48:56 +0000300 uint8_t b[1];
Aditya Agarwal9abb0d62007-01-24 22:53:54 +0000301 trans_->readAll(b, 1);
Mark Sleecfc01932006-09-01 22:18:16 +0000302 byte = *(int8_t*)b;
Mark Slee8d7e1f62006-06-07 06:48:56 +0000303 return 1;
Mark Sleee8540632006-05-30 09:24:40 +0000304}
305
Mark Slee4af6ed72006-10-25 19:02:49 +0000306uint32_t TBinaryProtocol::readI16(int16_t& i16) {
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000307 uint8_t b[2];
Aditya Agarwal9abb0d62007-01-24 22:53:54 +0000308 trans_->readAll(b, 2);
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000309 i16 = *(int16_t*)b;
310 i16 = (int16_t)ntohs(i16);
311 return 2;
312}
313
Mark Slee4af6ed72006-10-25 19:02:49 +0000314uint32_t TBinaryProtocol::readI32(int32_t& i32) {
Mark Slee8d7e1f62006-06-07 06:48:56 +0000315 uint8_t b[4];
Aditya Agarwal9abb0d62007-01-24 22:53:54 +0000316 trans_->readAll(b, 4);
Mark Slee8d7e1f62006-06-07 06:48:56 +0000317 i32 = *(int32_t*)b;
318 i32 = (int32_t)ntohl(i32);
319 return 4;
Mark Sleee8540632006-05-30 09:24:40 +0000320}
321
Mark Slee4af6ed72006-10-25 19:02:49 +0000322uint32_t TBinaryProtocol::readI64(int64_t& i64) {
Mark Slee8d7e1f62006-06-07 06:48:56 +0000323 uint8_t b[8];
Aditya Agarwal9abb0d62007-01-24 22:53:54 +0000324 trans_->readAll(b, 8);
Mark Slee8d7e1f62006-06-07 06:48:56 +0000325 i64 = *(int64_t*)b;
326 i64 = (int64_t)ntohll(i64);
327 return 8;
Mark Sleee8540632006-05-30 09:24:40 +0000328}
329
Mark Slee4af6ed72006-10-25 19:02:49 +0000330uint32_t TBinaryProtocol::readDouble(double& dub) {
Mark Slee4f261c52007-04-13 00:33:24 +0000331 BOOST_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t));
332 BOOST_STATIC_ASSERT(std::numeric_limits<double>::is_iec559);
333
334 uint64_t bits;
Mark Sleec98d0502006-09-06 02:42:25 +0000335 uint8_t b[8];
Aditya Agarwal9abb0d62007-01-24 22:53:54 +0000336 trans_->readAll(b, 8);
Mark Slee4f261c52007-04-13 00:33:24 +0000337 bits = *(uint64_t*)b;
338 bits = ntohll(bits);
339 dub = bitwise_cast<double>(bits);
Mark Sleec98d0502006-09-06 02:42:25 +0000340 return 8;
341}
342
Mark Slee4af6ed72006-10-25 19:02:49 +0000343uint32_t TBinaryProtocol::readString(string& str) {
Mark Sleef3c322b2006-06-26 23:52:22 +0000344 uint32_t result;
Mark Sleecfc01932006-09-01 22:18:16 +0000345 int32_t size;
Mark Slee4af6ed72006-10-25 19:02:49 +0000346 result = readI32(size);
Mark Sleecfc01932006-09-01 22:18:16 +0000347
Mark Sleef9831082007-02-20 20:59:21 +0000348 // Catch error cases
349 if (size < 0) {
350 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
351 }
352 if (string_limit_ > 0 && size > string_limit_) {
353 throw TProtocolException(TProtocolException::SIZE_LIMIT);
354 }
355
356 // Catch empty string case
357 if (size == 0) {
358 str = "";
359 return result;
360 }
Mark Slee6e536442006-06-30 18:28:50 +0000361
362 // Use the heap here to prevent stack overflow for v. large strings
Mark Sleef9831082007-02-20 20:59:21 +0000363 if (size > string_buf_size_ || string_buf_ == NULL) {
364 string_buf_ = (uint8_t*)realloc(string_buf_, (uint32_t)size);
365 if (string_buf_ == NULL) {
366 string_buf_size_ = 0;
367 throw TProtocolException(TProtocolException::UNKNOWN, "Out of memory in TBinaryProtocol::readString");
368 }
369 string_buf_size_ = size;
370 }
371 trans_->readAll(string_buf_, size);
372 str = string((char*)string_buf_, size);
Mark Slee6e536442006-06-30 18:28:50 +0000373
Mark Sleef3c322b2006-06-26 23:52:22 +0000374 return result + (uint32_t)size;
Mark Sleee8540632006-05-30 09:24:40 +0000375}
Mark Sleecfc01932006-09-01 22:18:16 +0000376
Marc Slemko6f038a72006-08-03 18:58:09 +0000377}}} // facebook::thrift::protocol