1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #ifndef _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_
21 #define _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_ 1
22 
23 #include <thrift/protocol/TBinaryProtocol.h>
24 #include <thrift/transport/TTransportException.h>
25 
26 #include <limits>
27 
28 #include <netinet/in.h>
29 
30 namespace apache {
31 namespace thrift {
32 namespace protocol {
33 
34 template <class Transport_, class ByteOrder_>
writeMessageBegin(const std::string & name,const TMessageType messageType,const int32_t seqid)35 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeMessageBegin(const std::string& name,
36                                                                      const TMessageType messageType,
37                                                                      const int32_t seqid) {
38   if (this->strict_write_) {
39     int32_t version = (VERSION_1) | ((int32_t)messageType);
40     uint32_t wsize = 0;
41     wsize += writeI32(version);
42     wsize += writeString(name);
43     wsize += writeI32(seqid);
44     return wsize;
45   } else {
46     uint32_t wsize = 0;
47     wsize += writeString(name);
48     wsize += writeByte((int8_t)messageType);
49     wsize += writeI32(seqid);
50     return wsize;
51   }
52 }
53 
54 template <class Transport_, class ByteOrder_>
writeMessageEnd()55 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeMessageEnd() {
56   return 0;
57 }
58 
59 template <class Transport_, class ByteOrder_>
writeStructBegin(const char * name)60 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeStructBegin(const char* name) {
61   (void)name;
62   return 0;
63 }
64 
65 template <class Transport_, class ByteOrder_>
writeStructEnd()66 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeStructEnd() {
67   return 0;
68 }
69 
70 template <class Transport_, class ByteOrder_>
writeFieldBegin(const char * name,const TType fieldType,const int16_t fieldId)71 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeFieldBegin(const char* name,
72                                                                    const TType fieldType,
73                                                                    const int16_t fieldId) {
74   (void)name;
75   uint32_t wsize = 0;
76   wsize += writeByte((int8_t)fieldType);
77   wsize += writeI16(fieldId);
78   return wsize;
79 }
80 
81 template <class Transport_, class ByteOrder_>
writeFieldEnd()82 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeFieldEnd() {
83   return 0;
84 }
85 
86 template <class Transport_, class ByteOrder_>
writeFieldStop()87 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeFieldStop() {
88   return writeByte((int8_t)T_STOP);
89 }
90 
91 template <class Transport_, class ByteOrder_>
writeMapBegin(const TType keyType,const TType valType,const uint32_t size)92 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeMapBegin(const TType keyType,
93                                                                  const TType valType,
94                                                                  const uint32_t size) {
95   uint32_t wsize = 0;
96   wsize += writeByte((int8_t)keyType);
97   wsize += writeByte((int8_t)valType);
98   wsize += writeI32((int32_t)size);
99   return wsize;
100 }
101 
102 template <class Transport_, class ByteOrder_>
writeMapEnd()103 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeMapEnd() {
104   return 0;
105 }
106 
107 template <class Transport_, class ByteOrder_>
writeListBegin(const TType elemType,const uint32_t size)108 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeListBegin(const TType elemType,
109                                                                   const uint32_t size) {
110   uint32_t wsize = 0;
111   wsize += writeByte((int8_t)elemType);
112   wsize += writeI32((int32_t)size);
113   return wsize;
114 }
115 
116 template <class Transport_, class ByteOrder_>
writeListEnd()117 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeListEnd() {
118   return 0;
119 }
120 
121 template <class Transport_, class ByteOrder_>
writeSetBegin(const TType elemType,const uint32_t size)122 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeSetBegin(const TType elemType,
123                                                                  const uint32_t size) {
124   uint32_t wsize = 0;
125   wsize += writeByte((int8_t)elemType);
126   wsize += writeI32((int32_t)size);
127   return wsize;
128 }
129 
130 template <class Transport_, class ByteOrder_>
writeSetEnd()131 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeSetEnd() {
132   return 0;
133 }
134 
135 template <class Transport_, class ByteOrder_>
writeBool(const bool value)136 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeBool(const bool value) {
137   uint8_t tmp = value ? 1 : 0;
138   this->trans_->write(&tmp, 1);
139   return 1;
140 }
141 
142 template <class Transport_, class ByteOrder_>
writeByte(const int8_t byte)143 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeByte(const int8_t byte) {
144   this->trans_->write((uint8_t*)&byte, 1);
145   return 1;
146 }
147 
148 template <class Transport_, class ByteOrder_>
writeI16(const int16_t i16)149 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeI16(const int16_t i16) {
150   auto net = (int16_t)ByteOrder_::toWire16(i16);
151   this->trans_->write((uint8_t*)&net, 2);
152   return 2;
153 }
154 
155 template <class Transport_, class ByteOrder_>
writeI32(const int32_t i32)156 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeI32(const int32_t i32) {
157   auto net = (int32_t)ByteOrder_::toWire32(i32);
158   this->trans_->write((uint8_t*)&net, 4);
159   return 4;
160 }
161 
162 template <class Transport_, class ByteOrder_>
writeI64(const int64_t i64)163 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeI64(const int64_t i64) {
164   auto net = (int64_t)ByteOrder_::toWire64(i64);
165   this->trans_->write((uint8_t*)&net, 8);
166   return 8;
167 }
168 
169 template <class Transport_, class ByteOrder_>
writeDouble(const double dub)170 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeDouble(const double dub) {
171   static_assert(sizeof(double) == sizeof(uint64_t), "sizeof(double) == sizeof(uint64_t)");
172   static_assert(std::numeric_limits<double>::is_iec559, "std::numeric_limits<double>::is_iec559");
173 
174   auto bits = bitwise_cast<uint64_t>(dub);
175   bits = ByteOrder_::toWire64(bits);
176   this->trans_->write((uint8_t*)&bits, 8);
177   return 8;
178 }
179 
180 template <class Transport_, class ByteOrder_>
181 template <typename StrType>
writeString(const StrType & str)182 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeString(const StrType& str) {
183   if (str.size() > static_cast<size_t>((std::numeric_limits<int32_t>::max)()))
184     throw TProtocolException(TProtocolException::SIZE_LIMIT);
185   auto size = static_cast<uint32_t>(str.size());
186   uint32_t result = writeI32((int32_t)size);
187   if (size > 0) {
188     this->trans_->write((uint8_t*)str.data(), size);
189   }
190   return result + size;
191 }
192 
193 template <class Transport_, class ByteOrder_>
writeBinary(const std::string & str)194 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeBinary(const std::string& str) {
195   return TBinaryProtocolT<Transport_, ByteOrder_>::writeString(str);
196 }
197 
198 /**
199  * Reading functions
200  */
201 
202 template <class Transport_, class ByteOrder_>
readMessageBegin(std::string & name,TMessageType & messageType,int32_t & seqid)203 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readMessageBegin(std::string& name,
204                                                                     TMessageType& messageType,
205                                                                     int32_t& seqid) {
206   uint32_t result = 0;
207   int32_t sz;
208   result += readI32(sz);
209 
210   if (sz < 0) {
211     // Check for correct version number
212     int32_t version = sz & VERSION_MASK;
213     if (version != VERSION_1) {
214       throw TProtocolException(TProtocolException::BAD_VERSION, "Bad version identifier");
215     }
216     messageType = (TMessageType)(sz & 0x000000ff);
217     result += readString(name);
218     result += readI32(seqid);
219   } else {
220     if (this->strict_read_) {
221       throw TProtocolException(TProtocolException::BAD_VERSION,
222                                "No version identifier... old protocol client in strict mode?");
223     } else {
224       // Handle pre-versioned input
225       int8_t type;
226       result += readStringBody(name, sz);
227       result += readByte(type);
228       messageType = (TMessageType)type;
229       result += readI32(seqid);
230     }
231   }
232   return result;
233 }
234 
235 template <class Transport_, class ByteOrder_>
readMessageEnd()236 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readMessageEnd() {
237   return 0;
238 }
239 
240 template <class Transport_, class ByteOrder_>
readStructBegin(std::string & name)241 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readStructBegin(std::string& name) {
242   name = "";
243   return 0;
244 }
245 
246 template <class Transport_, class ByteOrder_>
readStructEnd()247 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readStructEnd() {
248   return 0;
249 }
250 
251 template <class Transport_, class ByteOrder_>
readFieldBegin(std::string & name,TType & fieldType,int16_t & fieldId)252 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readFieldBegin(std::string& name,
253                                                                   TType& fieldType,
254                                                                   int16_t& fieldId) {
255   (void)name;
256   uint32_t result = 0;
257   int8_t type;
258   result += readByte(type);
259   fieldType = (TType)type;
260   if (fieldType == T_STOP) {
261     fieldId = 0;
262     return result;
263   }
264   result += readI16(fieldId);
265   return result;
266 }
267 
268 template <class Transport_, class ByteOrder_>
readFieldEnd()269 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readFieldEnd() {
270   return 0;
271 }
272 
273 template <class Transport_, class ByteOrder_>
readMapBegin(TType & keyType,TType & valType,uint32_t & size)274 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readMapBegin(TType& keyType,
275                                                                 TType& valType,
276                                                                 uint32_t& size) {
277   int8_t k, v;
278   uint32_t result = 0;
279   int32_t sizei;
280   result += readByte(k);
281   keyType = (TType)k;
282   result += readByte(v);
283   valType = (TType)v;
284   result += readI32(sizei);
285   if (sizei < 0) {
286     throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
287   } else if (this->container_limit_ && sizei > this->container_limit_) {
288     throw TProtocolException(TProtocolException::SIZE_LIMIT);
289   }
290   size = (uint32_t)sizei;
291 
292   TMap map(keyType, valType, size);
293   checkReadBytesAvailable(map);
294 
295   return result;
296 }
297 
298 template <class Transport_, class ByteOrder_>
readMapEnd()299 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readMapEnd() {
300   return 0;
301 }
302 
303 template <class Transport_, class ByteOrder_>
readListBegin(TType & elemType,uint32_t & size)304 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readListBegin(TType& elemType, uint32_t& size) {
305   int8_t e;
306   uint32_t result = 0;
307   int32_t sizei;
308   result += readByte(e);
309   elemType = (TType)e;
310   result += readI32(sizei);
311   if (sizei < 0) {
312     throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
313   } else if (this->container_limit_ && sizei > this->container_limit_) {
314     throw TProtocolException(TProtocolException::SIZE_LIMIT);
315   }
316   size = (uint32_t)sizei;
317 
318   TList list(elemType, size);
319   checkReadBytesAvailable(list);
320 
321   return result;
322 }
323 
324 template <class Transport_, class ByteOrder_>
readListEnd()325 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readListEnd() {
326   return 0;
327 }
328 
329 template <class Transport_, class ByteOrder_>
readSetBegin(TType & elemType,uint32_t & size)330 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readSetBegin(TType& elemType, uint32_t& size) {
331   int8_t e;
332   uint32_t result = 0;
333   int32_t sizei;
334   result += readByte(e);
335   elemType = (TType)e;
336   result += readI32(sizei);
337   if (sizei < 0) {
338     throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
339   } else if (this->container_limit_ && sizei > this->container_limit_) {
340     throw TProtocolException(TProtocolException::SIZE_LIMIT);
341   }
342   size = (uint32_t)sizei;
343 
344   TSet set(elemType, size);
345   checkReadBytesAvailable(set);
346 
347   return result;
348 }
349 
350 template <class Transport_, class ByteOrder_>
readSetEnd()351 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readSetEnd() {
352   return 0;
353 }
354 
355 template <class Transport_, class ByteOrder_>
readBool(bool & value)356 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readBool(bool& value) {
357   uint8_t b[1];
358   this->trans_->readAll(b, 1);
359   value = *(int8_t*)b != 0;
360   return 1;
361 }
362 
363 template <class Transport_, class ByteOrder_>
readByte(int8_t & byte)364 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readByte(int8_t& byte) {
365   uint8_t b[1];
366   this->trans_->readAll(b, 1);
367   byte = *(int8_t*)b;
368   return 1;
369 }
370 
371 template <class Transport_, class ByteOrder_>
readI16(int16_t & i16)372 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readI16(int16_t& i16) {
373   union bytes {
374     uint8_t b[2];
375     int16_t all;
376   } theBytes;
377   this->trans_->readAll(theBytes.b, 2);
378   i16 = (int16_t)ByteOrder_::fromWire16(theBytes.all);
379   return 2;
380 }
381 
382 template <class Transport_, class ByteOrder_>
readI32(int32_t & i32)383 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readI32(int32_t& i32) {
384   union bytes {
385     uint8_t b[4];
386     int32_t all;
387   } theBytes;
388   this->trans_->readAll(theBytes.b, 4);
389   i32 = (int32_t)ByteOrder_::fromWire32(theBytes.all);
390   return 4;
391 }
392 
393 template <class Transport_, class ByteOrder_>
readI64(int64_t & i64)394 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readI64(int64_t& i64) {
395   union bytes {
396     uint8_t b[8];
397     int64_t all;
398   } theBytes;
399   this->trans_->readAll(theBytes.b, 8);
400   i64 = (int64_t)ByteOrder_::fromWire64(theBytes.all);
401   return 8;
402 }
403 
404 template <class Transport_, class ByteOrder_>
readDouble(double & dub)405 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readDouble(double& dub) {
406   static_assert(sizeof(double) == sizeof(uint64_t), "sizeof(double) == sizeof(uint64_t)");
407   static_assert(std::numeric_limits<double>::is_iec559, "std::numeric_limits<double>::is_iec559");
408 
409   union bytes {
410     uint8_t b[8];
411     uint64_t all;
412   } theBytes;
413   this->trans_->readAll(theBytes.b, 8);
414   theBytes.all = ByteOrder_::fromWire64(theBytes.all);
415   dub = bitwise_cast<double>(theBytes.all);
416   return 8;
417 }
418 
419 template <class Transport_, class ByteOrder_>
420 template <typename StrType>
readString(StrType & str)421 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readString(StrType& str) {
422   uint32_t result;
423   int32_t size;
424   result = readI32(size);
425   return result + readStringBody(str, size);
426 }
427 
428 template <class Transport_, class ByteOrder_>
readBinary(std::string & str)429 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readBinary(std::string& str) {
430   return TBinaryProtocolT<Transport_, ByteOrder_>::readString(str);
431 }
432 
433 template <class Transport_, class ByteOrder_>
434 template <typename StrType>
readStringBody(StrType & str,int32_t size)435 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readStringBody(StrType& str, int32_t size) {
436   uint32_t result = 0;
437 
438   // Catch error cases
439   if (size < 0) {
440     throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
441   }
442   if (this->string_limit_ > 0 && size > this->string_limit_) {
443     throw TProtocolException(TProtocolException::SIZE_LIMIT);
444   }
445 
446   // Catch empty string case
447   if (size == 0) {
448     str.clear();
449     return result;
450   }
451 
452   // Try to borrow first
453   const uint8_t* borrow_buf;
454   uint32_t got = size;
455   if ((borrow_buf = this->trans_->borrow(nullptr, &got))) {
456     str.assign((const char*)borrow_buf, size);
457     this->trans_->consume(size);
458     return size;
459   }
460 
461   str.resize(size);
462   this->trans_->readAll(reinterpret_cast<uint8_t*>(&str[0]), size);
463   return (uint32_t)size;
464 }
465 
466 // Return the minimum number of bytes a type will consume on the wire
467 template <class Transport_, class ByteOrder_>
getMinSerializedSize(TType type)468 int TBinaryProtocolT<Transport_, ByteOrder_>::getMinSerializedSize(TType type)
469 {
470   switch (type)
471   {
472       case T_STOP: return 0;
473       case T_VOID: return 0;
474       case T_BOOL: return sizeof(int8_t);
475       case T_BYTE: return sizeof(int8_t);
476       case T_DOUBLE: return sizeof(double);
477       case T_I16: return sizeof(short);
478       case T_I32: return sizeof(int);
479       case T_I64: return sizeof(long);
480       case T_STRING: return sizeof(int);  // string length
481       case T_STRUCT: return 0;  // empty struct
482       case T_MAP: return sizeof(int);  // element count
483       case T_SET: return sizeof(int);  // element count
484       case T_LIST: return sizeof(int);  // element count
485       default: throw TProtocolException(TProtocolException::UNKNOWN, "unrecognized type code");
486   }
487 }
488 
489 }
490 }
491 } // apache::thrift::protocol
492 
493 #endif // #ifndef _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_
494